poj 1390 Blocks (区间dp)

来源:互联网 发布:数控编程毕业论文 编辑:程序博客网 时间:2024/06/08 16:31

Blocks
Time Limit: 5000MS Memory Limit: 65536KTotal Submissions: 5228 Accepted: 2153

Description

Some of you may have played a game called 'Blocks'. There are n blocks in a row, each box has a color. Here is an example: Gold, Silver, Silver, Silver, Silver, Bronze, Bronze, Bronze, Gold. 
The corresponding picture will be as shown below: 
 
Figure 1

If some adjacent boxes are all of the same color, and both the box to its left(if it exists) and its right(if it exists) are of some other color, we call it a 'box segment'. There are 4 box segments. That is: gold, silver, bronze, gold. There are 1, 4, 3, 1 box(es) in the segments respectively. 

Every time, you can click a box, then the whole segment containing that box DISAPPEARS. If that segment is composed of k boxes, you will get k*k points. for example, if you click on a silver box, the silver segment disappears, you got 4*4=16 points. 

Now let's look at the picture below: 
 
Figure 2


The first one is OPTIMAL. 

Find the highest score you can get, given an initial state of this game. 

Input

The first line contains the number of tests t(1<=t<=15). Each case contains two lines. The first line contains an integer n(1<=n<=200), the number of boxes. The second line contains n integers, representing the colors of each box. The integers are in the range 1~n.

Output

For each test case, print the case number and the highest possible score.

Sample Input

291 2 2 2 2 3 3 3 111

Sample Output

Case 1: 29Case 2: 1

Source

Liu Rujia@POJ

[Submit]   [Go Back]   [Status]   [Discuss]



题目大意:Jimmy最近迷上了一款叫做方块消除的游戏. 游戏规则如下:n个带颜色方格排成一列,相同颜色的方块连成一个区域(如果两个相邻的方块颜色相同,则这两个方块属于同一个区域). 游戏时,你可以任选一个区域消去.设这个区域包含的方块数为x,则将得到x^2的分值.方块消去之后,右边的方格将向左移动.虽然游戏很简单,但是要得到高分也不是很容易.Jimmy希望你帮助他找出最高可以得到多少分.

题解:区间dp

开始我们可以预处理,将颜色相同的连续段合并成一个点,并记录这个点代表的这一段的实际长度len[i],然后预处理出每次点相同颜色的前驱,方便之后的dp

f[i][j][k]消除i-j这一段,并且j后面连着k个与j颜色相同的一起被消掉的最大价值。

每次有两种消除方法:

(1)将i-(j-1)消除掉且后面没有连着的,然后将j与他后面连着的k个相同颜色的一起消掉。(需要注意的一点是,在这样计算的时候我们不确定j后面连着哪k个,我们只是假设他有k个,求此时的最高得分)

(2)我们考虑将j与i-j区间中的一段与j相同颜色的连在一起消去。f[i][j][k]=max(f[i][l][k+len[j]]+f[l+1][j-1][0]).考虑为什么是对的,f[i][l][k+len[j]]是之前已经预算过的,注意他表示的是l后连着k+len[j]个颜色相同的,然后一块消去len[j]+len[l]+k个,因为l+1-j-1段完全消除是后面没有跟着的,所以k个一定出自j之后。  

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define N 203using namespace std;int t,n,m,f[N][N][N];int col[N],len[N],point[N],next[N*10];int pow(int x){return x*x;}int main(){scanf("%d",&t);for (int T=1;T<=t;T++){scanf("%d",&m); n=0; int pre=0;for (int i=1;i<=m;i++){int x; scanf("%d",&x);if (x!=pre)  col[++n]=x,len[n]=1;else len[n]++;}memset(point,0,sizeof(point));memset(next,0,sizeof(next));memset(f,0,sizeof(f)); int tot=0;for (int i=1;i<=n;i++) next[++tot]=point[col[i]],point[col[i]]=i;for (int len1=1;len1<=n;len1++)  for (int i=1;i<=n;i++){ if (i+len1-1>n) break; int j=i+len1-1; for (int k=0;k<=tot;k++){ f[i][j][k]=f[i][j-1][0]+pow(len[j]+k); for (int l=next[j];l>=i;l=next[l]) { if (l>j) continue;  f[i][j][k]=max(f[i][j][k],f[i][l][k+len[j]]+f[l+1][j-1][0]);     } } }printf("Case %d: %d\n",T,f[1][n][0]);}}

当然还有另一种方法,而且比上面的方法跑的更快更稳定。

f[i][j][k]表示i-j这一段消到只剩下k个,且i,j与这k个块的颜色都相同。

g[i][j]表示把i-j这一段全部消掉的最高得分。

f[i][j][k]=max(f[i][l][k-1]+g[l+1][j-1]) 表示把l+1-j-1段完全消除,使j与前面颜色相同的k-1个合并,注意枚举的l必须与i,j颜色相同。

g[i][j]=max(g[i][l]+g[l+1][j],f[i][j][k]+k^2) 可以将i-j从中间断开分别消除,也可以将i-j剩下的k个一次消除。

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define N 203using namespace std;int t,n,m,f[N][N][N],g[N][N];int col[N],len[N],point[N],next[N*10];int pow(int x){return x*x;}int main(){freopen("a.in","r",stdin);scanf("%d",&t);for (int T=1;T<=t;T++){scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&col[i]);memset(f,128,sizeof(f)); memset(g,0,sizeof(g));for (int i=1;i<=n;i++) f[i][i][1]=0,f[i][i][0]=0,g[i][i]=1;for (int i=n;i>=1;i--) for (int j=i+1;j<=n;j++) {  if (col[i]==col[j])  for (int k=1;k<=n;k++)   {     if (j-i+1<k) break;      for (int l=i;l<j;l++)     if (col[i]==col[l])   f[i][j][k]=max(f[i][j][k],f[i][l][k-1]+g[l+1][j-1]);    g[i][j]=max(g[i][j],f[i][j][k]+k*k);   }  for (int l=i;l<j;l++) g[i][j]=max(g[i][j],g[i][l]+g[l+1][j]);     }printf("Case %d: %d\n",T,g[1][n]);}}



1 0
原创粉丝点击