poj 1390 Blocks

题目大意:

给定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;
}
原文地址:https://www.cnblogs.com/jyhywh/p/6339506.html