码迷,mamicode.com
首页 > Windows程序 > 详细

AcWing 322. 消木块 区间dp+分治

时间:2020-03-31 14:48:06      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:win   ==   namespace   cas   间接   main   iostream   往里面   调用   

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=210;
int t,n;
int col[N],A[N],len[N],dp[N][N][N]; 
//dp[i][j][k]代表消除第 i~j 块且区间最右边留下了 k 个与 j 颜色相同的方块的最大价值
int solv(int l,int r,int last) {
    //如果左右端点相同了,那么就直接消除 
    if(l==r) 
        return (len[r]+last)*(len[r]+last);
    //如果之前搜过了,直接调用 
    if(dp[l][r][last]) 
        return dp[l][r][last];//记忆化
    //将 r~last 合并并消除,因为后面被消除,所以不存在与 r-1 颜色相同的
    //不存在与r-1颜色相同是因为,从原始数组的左右区间开始往里面递归的
    //再看下面的递推式子,会发现,r~las合并之后,后面就不会存在与r-1颜色相同的 
    dp[l][r][last]=solv(l,r-1,0)+(len[r]+last)*(len[r]+last);
    for(int i=l; i+1<=r-1; i++)
        if(A[i]==A[r])
            //消除 i+1~r-1 后合并 r~last 并删除 l~i 
            //分治,区间两边分开,先把右边的算完,那么再往右边的就会和左边的区间接上 
            dp[l][r][last]=max(dp[l][r][last],solv(l,i,len[r]+last)+solv(i+1,r-1,0));
    return dp[l][r][last];
}
int main() {
    scanf("%d",&t);
    for(int cases=1; cases<=t; cases++) {
        memset(col,0,sizeof col);
        memset(len,0,sizeof len);
        memset(A,0,sizeof A);
        memset(dp,0,sizeof dp);
        scanf("%d",&n);
        for(int i=1; i<=n; i++) 
            scanf("%d",&col[i]);
        int cnt=0;
        for(int i=1; i<=n; i++) {
            if(col[i]!=col[i-1]) 
                A[++cnt]=col[i],len[cnt]=1;
            else 
                //从当前位置开始,往后有几块连续和她相同 
                len[cnt]++;
        }
        printf("Case %d: %d\n",cases,solv(1,cnt,0));
    }
    return 0;
}


AcWing 322. 消木块 区间dp+分治

标签:win   ==   namespace   cas   间接   main   iostream   往里面   调用   

原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12604557.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!