您的位置:首页 > 其它

poj 1390 dp(方盒游戏)

2015-07-30 21:35 253 查看
题意:N个方盒(box)摆成一排,每个方盒有自己的颜色。连续摆放的同颜色方盒构成一个方盒片段(box segment)。比如共有四个方盒片段,每个方盒片段分别有 1、4、3、1个方盒,玩家每次点击一个方盒,则该方盒所在方盒片段就会消失。若消失的方盒片段中共有k个方盒,则玩家获得k*k个积分。问给定游戏开始时的状态,玩家可获得的最高积分是多少?

思路:首先进行预处理:将连续的若干个方块作为一个“大块”(box_segment) 考虑,假设开始一共有 n个“大块”,编号0到n-1,第i个大块的颜色是color[i],包含的方块数目,即长度,是len[i]。

首先尝试如果用click_box(i,j)表示从大块i到大块j这一段消除后所能得到的最高分,那么考虑最后一个大块j是自己删除还是和左边的某一个同色大块一起删除,似乎可以得到:click_box(i,j) = MAX{click_box(i,j-1) + len[j]*len[j] , click_box(i,k-1) + click_box(k+1,j-1) + (len[k]+len[j])2}。但是这样的想法是错误的,因为将大块k和大块j合并后,形成的新大块会在最右边。将该新大块直接将其消去的做法,才符合上述式子,但直接将其消去,未必是最好的,也许它还应该和左边的同色大块合并,才更好。所以上述求得的不是最有解。

那么此时考虑增加一维,考虑新的形式:click_box(i,j,ex_len),表示大块j的右边已经有一个长度为ex_len的大块(该大块可能是在合并过程中形成的,不妨就称其为ex_len),且j的颜色和ex_len 相同,在此情况下将 i 到j以及ex_len都消除所能得到的最高分。于是整个问题就是求:click_box(0,n-1,0)。

求click_box(i,j,ex_len)时,有两种处理方法,取最优者。假设j和ex_len合并后的大块称作 Q

1) 将Q直接消除,这种做法能得到的最高分就是: click_box(i,j-1,0) + (len[j]+ex_len)2

2) 期待Q以后能和左边的某个同色大块合并。需要枚举可能和Q 合并的大块。假设让大块k和Q合并,则此时能得到的最大分数是:

click_box(i,k,len[j]+ex_len) + click_box(k+1,j-1,0)。

click_box(i,j,ex_len) 的终止条件是i == j。

dp采用记忆化搜索的形式:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdlib>
using namespace std;
#define INF 0x3fffffff
#define clc(s,t) memset(s,t,sizeof(s))
#define N 205
int T,n,q=1;
int dp

,s
,len
,c
;
int solve(int a,int b,int x){
if(dp[a][b][x])
return dp[a][b][x];
if(a == b)
return dp[a][b][x] = (len[a]+x)*(len[a]+x);
dp[a][b][x] = solve(a,b-1,0)+(len[b]+x)*(len[b]+x);
for(int i = b-2;i>=a;i--)
if(c[i]==c[b])
dp[a][b][x] = max(dp[a][b][x],solve(a,i,len[b]+x)+solve(i+1,b-1,0));
return dp[a][b][x];
}
int main(){
scanf("%d",&T);
while(T--){
int i,j;
clc(dp,0);
scanf("%d",&n);
for(i = 0;i<n;i++)
scanf("%d",&s[i]);
for(i = 0,j=-1;i<n;i++){
if(i && s[i]==s[i-1]){
len[j]++;
continue;
}
c[++j] = s[i];
len[j] = 1;
}
solve(0,j,0);
printf("Case %d: %d\n",q++,dp[0][j][0]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: