您的位置:首页 > 其它

poj 1390 Blocks(DP)

2013-11-07 22:24 393 查看
题意:有n个方块排成一列,对于每个方块都有一种颜色。现在有一种消除规则,就是对于连续颜色相同的一行可以消去,且消去后右边的方块左移,并且效益为个数的平方。现在问你通过怎么的消除方式,可以使效益最大。

思路:  定义状态dp[a][b][c] 从第a个到第b个方块且第b个方块后连着c个与b相同颜色的方块最大的效益。

    状态转移:

    有两种决策:1)直接消除。

     dp[a][b][c]=dp[a][b-1][0]+(len[b]+c)*(len[b]+c);

    2)选取连接点,消除中间的,再连接继续消除。

   dp[a][b][c]=max(dp[a][b][c],dp[a][p][len[b]+c]+dp[p+1][c-1][0]);(a=<p<c)且(color[b]==color[p])

对于这一题,可以在读取时存下与当前块最近的颜色块的编号。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=222;//开小了会Re,因为他最多可以延长100个
int n;
int color[maxn];
int len[maxn];
int cnt;
int dp[maxn][maxn][maxn];
void input()
{
cnt=0;
scanf("%d",&n);
scanf("%d",&color[cnt]);
memset(len,0,sizeof(len));
len[cnt]++;
for(int i=1;i<n;i++)
{
int a;
scanf("%d",&a);
if(color[cnt]==a)
{
len[cnt]++;
}
else
{
cnt++;
len[cnt]++;
color[cnt]=a;
}
}
memset(dp,-1,sizeof(dp));
}
void dfs(int a,int b,int c)// dfs时用记忆化搜索,将DP值记录下来,否则会TLE
{
if(a>b)
{
return ;
}
if(a==b)
{
dp[a][b][c]=(len[a]+c)*(len[a]+c);
return ;
}
int res;
if(dp[a][b-1][0]==-1)
{
dfs(a,b-1,0);
}
res=dp[a][b-1][0]+(len[b]+c)*(len[b]+c);
for(int i=a;i<b;i++)
{
if(color[i]==color[b])
{
if(dp[a][i][len[b]+c]==-1) dfs(a,i,len[b]+c);
if(dp[i+1][b-1][0]==-1) dfs(i+1,b-1,0);
res=max(res,dp[a][i][len[b]+c]+dp[i+1][b-1][0]);
}
}
dp[a][b][c]=res;
}
int main()
{
// freopen("in.txt","r",stdin);
int t;
int cas=1;
scanf("%d",&t);
while(t--)
{
printf("Case %d: ",cas++);
input();
dfs(0,cnt,0);
printf("%d\n",dp[0][cnt][0]);
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  DP 线性DP