题目大意:
给定n个不同颜色的盒子,连续的相同颜色的k个盒子可以拿走,权值为k*k,求把所有盒子拿完的最大权值。
解题思路:
lrj大神黑书上的题,翻了别人的解题报告才做出来的
首先:合并初始相邻相同的块,得到颜色数组c和对应的长度len,例如 1 1 1 1 1 3 2 2 1 1 1 可记为color[ 1 ] = 1; len[1 ] = 5; color[ 2 ] = 3; len[ 2 ] =1; color[ 3 ] = 2; len[ 3 ] = 2; color[ 4 ] = 1; len[ 4 ] = 3;
然后:d[ i ] [ j ][ k ]表示i~j区间,与后面k个相同颜色块一起消除得分的最大值(当然k个块的颜色必须与j相同),写代码的时候,k段和 j 那段不必挨在一起,因为你本来就假设他们之间的那段被消掉了,
状态转移方程两种:
1.单独消除,dp[i][j][k]=dp[i][j-1][0]+(len[j]+k)^2;
2.和区间段(i,j)中的某一块进行消除(要颜色一样能消除),假设i < = p < j满足条件,则dp[i][j][k]=dp[i][p][k+len[j]]+dp[p+1][j-1][0]。
代码:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; int t,c[201],l[201],f[201][201][201],n,tot; int dp(int ll,int rr,int k) { if(f[ll][rr][k]) return f[ll][rr][k]; if(ll==rr) return (l[ll]+k)*(l[ll]+k); f[ll][rr][k]=dp(ll,rr-1,0)+(l[rr]+k)*(l[rr]+k); for(int i=ll;i<rr;i++) if(c[i]==c[rr]) f[ll][rr][k]=max(f[ll][rr][k],dp(ll,i,l[rr]+k)+dp(i+1,rr-1,0)); return f[ll][rr][k]; } int main() { int ca=0; scanf("%d",&t); while(t--) { memset(f,0,sizeof(f)); memset(l,0,sizeof(l)); scanf("%d",&n); int tmp; scanf("%d",&c[1]); l[1]++; tot=1; for(int i=1,j=1;i<n;i++) { scanf("%d",&tmp); if(c[j]==tmp) l[j]++; else { j++; tot=j; c[j]=tmp; l[j]++; } } printf("Case %d: %d ",++ca,dp(1,tot,0)); } return 0; }