poj 1390 Blocks(dp,黑书dp方块消除)


poj 1390 Blocks


先将本来就连在一起的方块看做一个整体,记录颜色,长度

dp[l][r][k],选择[l,r]这一段的方块,根据[l,r]最右的块进行两种决策,k是当前选择颜色块的累加长度

1:直接将r块消除 dp[l][r-1][0]+(len+k)^2

2:在r之前寻找同r一个颜色的块(p)然后一起消除 dp[ l ][ p ][ k + len[ r ]  ]+dp[ p + 1 ][ r - 1][ 0 ]


状态转移太巧妙了,刚开始看的时候一直看不懂那个k


#include<stdio.h>
#include<string.h>
#define MAXN 205
int color[MAXN],len[MAXN],up;
int dp[MAXN][MAXN][MAXN];
int max(int a,int b) {return a>b?a:b;}
//选取的一段格子的左边界、右边界、当前选取的同一种颜色的格子总长度
int d(int l,int r,int k)
{
    if(l>r) return 0;
    if(dp[l][r][k]!=-1) return dp[l][r][k];
    
    int ans=0;
    //直接消除当前选取的同一种颜色
    ans=max(ans,d(l,r-1,0)+(k+len[r])*(k+len[r]));
    //寻找同当前颜色一样的段一同消除
    for(int i=l;i<r;i++)
    {
        if(color[i]==color[r])
            ans=max(ans,d(l,i,k+len[r])+d(i+1,r-1,0));
    }
    dp[l][r][k]=ans;
    return ans;
}
int main()
{
    int cas,n,x;
    color[0]=-1;
    scanf("%d",&cas);
    for(int k=1;k<=cas;k++)
    {
        scanf("%d",&n);
        memset(len,0,sizeof(len));
        memset(dp,-1,sizeof(dp));
        up=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            if(x==color[up])
                len[up]++;
            else
                up++,
                color[up]=x,
                len[up]=1;
        }
        printf("Case %d: %d\n",k,d(1,up,0));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值