[POJ1390]Blocks(dp)

来源:互联网 发布:淘宝代销刷单 编辑:程序博客网 时间:2024/06/01 23:34

题目描述

传送门

题解

这道dp想了很久都没有思路。这种消来消去的题目感觉用dp没法搞吖。
果然我还是太弱。

记忆化搜索的方法是看了网上的题解的。不过还是盯着那个状态看了很久才勉强理解。f(l,r,k)表示将l到r这一段区间并且连同r后面的k个和r相同颜色的方块都消完的最大得分。那么f(l,r,k)=max{f(l,r1,0)+(k+1)2,f(l,i,k+1)+f(i+1,r1,0)}
实际上我认为这个转移很难理解。不过不想那么多的话也许更好想一点,其实就是分类讨论,f(l,r1,0)+(k+1)2表示将k+1个连着一起消掉,f(l,i,k+1)+f(i+1,r1,0)则表示分成两部分消掉。

但是TA的方法更稳一点,而且更好理解。f(l,r,k)要求l,r颜色相同,表示将l~r这一段消到只剩k个和lr颜色相同的点的最大得分,g(l,r)表示将lr这一段全部消去的最大得分。
那么f(l,r,k)=max{f(l,r,k),f(l,i,k1)+g(i+1,r1)}g(l,r)=max{f(l,r,k)+kk,g(l,i)+g(i+1,r)}
时间复杂度O(n4),不过是可以过的。

代码

#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define N 205int T,n,Case;int color[N],f[N][N][N];int dp(int l,int r,int k){    if (l>r) return 0;    if (f[l][r][k]) return f[l][r][k];    f[l][r][k]=dp(l,r-1,0)+(k+1)*(k+1);    for (int i=r-1;i>=l;--i)        if (color[i]==color[r])            f[l][r][k]=max(f[l][r][k],dp(l,i,k+1)+dp(i+1,r-1,0));    return f[l][r][k];}int main(){    scanf("%d",&T);    while (T--)    {        scanf("%d",&n);        for (int i=1;i<=n;++i) scanf("%d",&color[i]);        memset(f,0,sizeof(f));        printf("Case %d: %d\n",++Case,dp(1,n,0));    }}

Orz TA

#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define N 205int T,n,Case;int color[N],tot[N][N],f[N][N][N],g[N][N];void clear(){    n=0;    memset(f,128,sizeof(f)); memset(g,0,sizeof(g));    memset(tot,0,sizeof(tot));memset(color,0,sizeof(color));}int main(){    scanf("%d",&T);    while (T--)    {        clear();        scanf("%d",&n);        for (int i=1;i<=n;++i) scanf("%d",&color[i]);        for (int i=1;i<=n;++i)            for (int j=i+1;j<=n;++j)                if (color[i]==color[j])                    for (int k=i;k<=j;++k)                        if (color[k]==color[i]) tot[i][j]++;        memset(f,128,sizeof(f)); memset(g,0,sizeof(g));        for (int i=1;i<=n;++i) f[i][i][0]=1,f[i][i][1]=0,g[i][i]=1;        for (int len=2;len<=n;++len)            for (int l=1;l<=n-len+1;++l)            {                int r=l+len-1;                if (color[l]==color[r])                    for (int k=1;k<=tot[l][r];++k)                    {                        for (int i=l;i<r;++i)                            f[l][r][k]=max(f[l][r][k],f[l][i][k-1]+g[i+1][r-1]);                        g[l][r]=max(g[l][r],f[l][r][k]+k*k);                    }                for (int i=l;i<r;++i)                    g[l][r]=max(g[l][r],g[l][i]+g[i+1][r]);                f[l][r][0]=g[l][r];            }        printf("Case %d: %d\n",++Case,g[1][n]);    }}

总结

0 0