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.