http://acm.uva.es/archive/nuevoportal/region.php?r=as9&year=2010
The problem can be reduced to this -
Find minimum number of push operations needed to build a number sequence by printing the top element of the stack.For example, if the sequence to be built is -
1 2 1 1 3 2 1We can do it through the following steps -
- Push 1 into stack and print top [Current Stack : 1]
- Push 2 into stack and print top [Current Stack : 1 2]
- Push 1 into stack, print top twice and pop it from stack [Current Stack : 1 2]
- Push 3 into stack, print top and pop it from stack [Current Stack : 1 2]
- Print top & pop 2 from stack [Current Stack : 1]
- Print top [Current Stack : 1]
I have used dynamic programming to solve this problem. The key idea is to optimally use push and pop operations so that we can re-use elements from the stack. Note that if we want to re-use a portion of the stack, like '1 5 2', these elements need to appear in that order as a subsequence of the original sequence and in reverse order (2 5 1) from the element where the first subsequence ended.
When we're trying to find optimal solution between 2 start and end indexes of the sequence, we have the following options -
- Push, print and pop the first element of the sequence. Find the optimal solution for the rest of the sequence.
- Find the optimal solution for the sequence [start, end-1] and then push, print and pop the last element.
- For each element that matches the first number, we can push the first number into the stack and try to optimally solve the 2 subsequence created before and after the element we're considering.
The source code would certainly make things more clear -
/* Problem Name : Halloween Costumes Problem Number : Archive 4857 Link : http://acm.uva.es/archive/nuevoportal/region.php?r=as9&year=2010 Problemsetter : Manzurur Rahman Khan Problem Type : Dynamic Programming, Building a sequence using stack operations (minimum number of pushes) Difficulty : Medium Complexity : O(N^3) Date : November 10, 2010 */ #include <stdio.h> #define rep(i,n) for(i = 0; i < (n); i++) #define min(a,b) (((a)<(b))?(a):(b)) #define MAXN 100 #define INF 10234567 int N,M; int ct[MAXN+2]; //original input array int c[MAXN+2]; //sanitized input array int dp[MAXN+2][MAXN+2]; // create a new sequence such that same number does not appear consecutively // for example - 1 1 2 3 3 4 2 2 1 would become 1 2 3 4 2 1 void sanitize() { int i,j; int n = 0; rep(i,N) { c[n++] = ct[i]; for(j=i;j<N;j++) { if(ct[i] != ct[j]) break; } i = j - 1; } N = n; } // recursive function to calculate and memoize the result // a and b are start and end index of the sequence int go(int a, int b) { if(a > b) return 0; if(dp[a][b] < INF) return dp[a][b]; if(a == b || a+1 == b) return dp[a][b] = (b-a+1); int &ret = dp[a][b]; ret = min(ret, 1 + go(a+1,b)); ret = min(ret, 1 + go(a,b-1)); if(c[a] == c[b]) ret = min(ret, 1 + go(a+1,b-1)); int i; for(i = a+1; i <= b; i++) if(c[i] == c[a]) { ret = min(ret, 1 + min( go(a+1,i-1), go(a,i-1)-1 ) + min( go(i,b)-1, go(i+1,b) ) ); } return ret; } int main() { int T,kase=1; int i,j; int res; scanf(" %d",&T); while(T--) { scanf(" %d %d",&N,&M); rep(i,N) scanf(" %d",&ct[i]); sanitize(); rep(i,N) rep(j,N) dp[i][j] = INF; res = go(0,N-1); printf("Case %d: %d\n",kase++,res); } return 0; }
My main idea was if for some i , i>a if c[a]==c[i] then we can say if we want to reuse the a th cloth in ith party then before ith party all new cloths must be removed. So the result will be dfs(a+1,i-1)+dfs(i,b) . Also a special thing when I don't reuse the cloth 1+dfs(a+1,b). This was enough for me to get AC on the contest :)
ReplyDeleteBut Vaia what is the need of sanitize() func in your code?
I used base case :
Deleteif(a==b) return 1;
if(a>b) return 0;
if c[a]==c[i] , then transition into two states F(a,i-1) + F(i+1,b) , and also the last case.
Your equation is certainly cleaner. No wonder I needed several tries to get it correct :)
ReplyDeleteWhen I started thinking about this problem, first thing I did was to replace sequence of same numbers with one so that I need to worry about one less issue. Of course after finding the recursion it became irrelevant, but I kept the function anyway.