POJ 1390 Blocks 区间DP加状态参数

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/88931801

t i t l e title

POJ 1390
CH POJ1390
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

2
9
1 2 2 2 2 3 3 3 1
1
1

Sample Output

Case 1: 29
Case 2: 1

Source

Liu Rujia@POJ

a n a l y s i s analysis

区间 d p dp ,加状态参数。
如果只是用状态 d p ( i , j ) dp(i, j) 来描述消去方块 i i 到方块 j j 获得的分数是无法形成递推关系的。

因为在这个时候对于最右边的大块有两种选择:

  • 一是直接消去。
  • 二是将其与左边某个大块合并删除。

而对于选择二来说,删去未必是最优方案,也许还应该与左边的某方块合并后消去。
所以只有两个参数是无法准确描述状态并形成递推关系的。

解决方案就是“加参数” d p ( i , j , k ) dp(i, j, k) 表示消去方块 i &gt; j i-&gt;j
同时 j j 右边与 j j 同色的方块长度(也称之为个数)为 k k
此时递推关系:

  • 直接消去 j j :
    d p ( i , j , l e n ) = d p ( i , j 1 , 0 ) + ( s e g [ j ] . l e n + l e n ) ( s e g [ j ] . l e n + l e n ) ; dp(i,j,len)=dp(i,j-1,0)+(seg[j].len+len) * (seg[j].len+len);
  • j j 与左边某个方块 k k 合并:
    d p ( i , j , l e n ) = d p ( k + 1 , j 1 , 0 ) + d p ( i , k , l e n [ j ] + l e n ) ; dp(i,j,len)=dp(k+1,j-1,0)+dp(i,k,len[j]+len);

note:
在选择方块序号 k k 时注意循环边界处理
——摘自林伏案

c o d e code

#include<bits/stdc++.h>
using namespace std;
const int maxn=205;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
struct Segment
{
	int color,len;
	Segment (int c,int l) : color(c), len(l) {};
	Segment () {};
}seg[maxn];
int f[maxn][maxn][maxn];
int block[maxn];
inline int dp(int fr,int to,int len)
{
	if (f[fr][to][len]!=-1)
		return f[fr][to][len];
	if (fr==to)
		return f[fr][to][len]=(seg[to].len+len)*(seg[to].len+len);
	int ans=dp(fr,to-1,0)+(seg[to].len+len)*(seg[to].len+len);
	for (int i=fr; i<to; ++i)
		if (seg[i].color==seg[to].color)
			ans=max(ans,dp(i+1,to-1,0)+dp(fr,i,seg[to].len+len));
	return f[fr][to][len]=ans;
}
int main()
{
	int t,kase=0;read(t);
	while (t--)
	{
		memset(f,-1,sizeof(f));
		int n;read(n);
		for (int i=1; i<=n; ++i)
			read(block[i]);
		int dep=0;
		seg[dep]=Segment(block[1],1);
		for (int i=2; i<=n; ++i)
			if (block[i]==block[i-1]) ++seg[dep].len;
			else seg[++dep]=Segment(block[i],1);
		printf("Case %d: %d\n",++kase,dp(0,dep,0));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/88931801