poj 1390 dp(方盒游戏)

来源:互联网 发布:mysql 5.6参考手册 编辑:程序博客网 时间:2024/05/29 16:16

题意: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 205int T,n,q=1;int dp[N][N][N],s[N],len[N],c[N];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;}


0 0
原创粉丝点击