HDU - 6212 Zuma 区间dp

Think about the Zuma Game. You have a row of at most 200200 black(0) or white(1) balls on the table at the start. Each three consecutive balls never share the same colour. You also have infinite amount of black and white balls in your hand. On each turn, you can choose a ball in your hand and insert it into the row, including the leftmost place and the rightmost place. Then, if there is a group of three of more balls in the same colour touching, remove these balls. Keep doing this until no more balls can be removed. 
Find the minimal balls you have to insert to remove all the balls on the table.

Input

The first line of input contains an integer T (1≤T≤100)T (1≤T≤100) which is the total number of test cases. 
Each test case contains a line with a non-empty string of 00 and 11 describing the row of balls at the start.

Output

For each test case, output the case number and the minimal balls required to insert in a line.

Sample Input

4
10101
101001001
1001001001
01001101011001100

Sample Output

Case #1: 4
Case #2: 3
Case #3: 3
Case #4: 2

题解:先保存相同的区间长度,区间合并的时候有三种情况

1.直接求,枚举区间各点

2.打掉中间的之后,两边的相遇会消掉,这个时候要满足中间的颜色差别为奇数,才能满足两边颜色相同,如果两边和大约3直接消除,否则+1

3.以中间某一个为分界线,打掉左子区间和右子区间,左中右合并,这个时候在满足2的条件下,还要满足。枚举的断点为与左右端点颜色相同,并且该点区间颜色个数为1,因为如果大约等于2的话 打掉左右一个区间后,就会和中间的消除 这个地方错了好多次 ,注意!!!

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 1e5+10;

int dp[210][210],num[210];
char s[210];
int main(){
	int T;
	int nn = 1;
	scanf("%d", &T);
	while(T--){
		scanf("%s", s);
		int len = strlen(s);
		printf("Case #%d: ", nn++);
		int cnt = 1;
		num[1] = 1;
		memset(dp, INF, sizeof(dp));
		for(int i = 1; i < len; i++){ //相同颜色个数统计
			if(s[i] == s[i-1]) num[cnt]++;
			else num[++cnt] = 1;
		}
		for(int l = 0; l < cnt ; l++){
			for(int i = 1; i <= cnt - l; i++){
				int j = i + l;
				if(l == 0){
					dp[i][i] = 3 - num[i];
				}else{
					for(int k = i; k < j; k++) // 区间合并第一种
						dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
					if(l % 2 == 0){
						if(num[i] + num[j] == 2) // 第二种
							dp[i][j] = min(dp[i][j], dp[i + 1][j - 1] + 1);
						else
							dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
						if(num[i] + num[j] <= 3)  //第三种
							for(int k = i + 2; k < j; k += 2)
								if(num[k] == 1)
									dp[i][j] = min(dp[i][j], dp[i + 1][k - 1] + dp[k + 1][j - 1]);
					}
				}
			}
		}
		printf("%d\n", dp[1][cnt]);
	} 
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值