Codeforces 607B Zuma(区间DP)
题目大概说,有n个颜色的宝石,可以消除是回文串的连续颜色序列,问最少要几下才能全部消除。
- 自然想到dp[i][j]表示序列i...j全部消除的最少操作数
- 有几种消除的方式都能通过枚举k(i<=k<j)从min(dp[i][k],dp[k+1][j])转移
- 还有一种先消除中间的,剩余两部分组成回文串再消除,这种消除方式转移不会。。想到的时间复杂度太高。。
- 看了tourist的代码,发现神的转移好简洁,这种方式就是从dp[i+1][j-1](c[i]=c[j])转移的
- 应该可以这么理解,如果c[i]=c[j],而序列i+1...j-1消除到最后一步必定会剩下一个回文串!然后这个回文串就和c[i]和c[j]拼在一起,一起消除!感觉好强。。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int c[555],d[555][555]; 6 int main(){ 7 int n; 8 scanf("%d",&n); 9 for(int i=0; i<n; ++i){ 10 scanf("%d",c+i); 11 } 12 for(int i=0; i<n; ++i){ 13 d[i][i]=1; 14 for(int j=i+1; j<n; ++j){ 15 d[i][j]=11111111; 16 } 17 } 18 for(int len=2; len<=n; ++len){ 19 for(int i=0; i+len-1<n; ++i){ 20 int j=i+len-1; 21 for(int k=i; k<j; ++k){ 22 d[i][j]=min(d[i][j],d[i][k]+d[k+1][j]); 23 } 24 if(c[i]==c[j] && len==2) d[i][j]=1; 25 else if(c[i]==c[j]) d[i][j]=min(d[i][j],d[i+1][j-1]); 26 } 27 } 28 printf("%d",d[0][n-1]); 29 return 0; 30 }