POJ 1390 Blocks(DP)

Description:

给出一排方块,每次可以选择一整块长度为len的颜色相同的方块(一个segment)消除,并获得分数len^2, 现在给出一排方块,问最多能得到多少分。

Input:

有多组数据,每组给出n,方块数,以及n各整数表示n块方块的颜色.

Output:

最大得分数

Analysis:

这个问题的递归特征还是很明显的,用dp的话,状态是最困难的。首先较为明显的是相同颜色的方块可以缩为一个segment,通常的想法是dp(i,j)表示消除从i到j的方块段最多可以获得多少积分,然而这样的话状态难以转移,因为,难以把多次的删去中间方块积累大的方块这种做法包括进去。其实可以加一维用dp(i,j,len)表示删去从i到j的方块且j的右边len个还有连续的与其颜色相同方块,这样就可以把多次积累的情况考虑进去了。状态转移方程为:dp(i,j,len)=max(dp(i,j-1,len+a[j].len)^2),dp(i,k,len+a[j].len)+dp(k+1,j-1,0) ) 其中a[k].color=a[j].color, k<j

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
#include<time.h>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 0xffffff0;
const int MOD = 1e9 + 7;
const int maxn = 205;
 
struct Segment {
	int color;
	int len;
};
Segment a[maxn];
int n;
int dp[maxn][maxn][maxn];
int DP(int i, int j, int len) {
 
	int & ans = dp[i][j][len];
	if (ans)return ans;
	ans = (a[j].len + len)*(a[j].len + len);
	if (i == j)return ans;
	ans += DP(i, j - 1, 0);
 
	for (int k = i; k <= j - 1; ++k) {
		if (a[k].color != a[j].color)continue;
		int r = DP(k + 1, j - 1, 0); 
		r+=DP(i, k, len + a[j].len);
		ans = max(r, ans);
	}
 
	return ans;
}
 
int main() {
	//freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
	//freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
	int T; scanf("%d", &T);
	int kase = 0;
	while (T--) {
		printf("Case %d: ", ++kase);
		scanf("%d", &n);
		int lastc = 0, num =0;
		for (int i = 0; i < n; ++i) {
			int c;
			scanf("%d", &c);
			if (c != lastc) {
				a[num].len = 1;
				a[num].color = c;
				lastc = c;
				num++;
			}
			else a[num-1].len++;
		}
		memset(dp, 0, sizeof(dp));
		printf("%d\n", DP(0, num-1, 0));
	}
 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/81542290