您的位置:首页 > 其它

CodeForces 149D 括号染色问题 dp+dfs好题

2013-12-12 20:36 309 查看
题意:给出一串已经匹配好的括号,现在要给它们上色,每个括号可以选择蓝色,红色,不上色三种情况,但是相邻的括号颜色不能相同,(可以同无色),每一对匹配的括号都有且仅有一个括号染色。

这题想了n久,今天做了半天终于给A掉了,感动得泪流满面。。。

题意不难理解,就是要想好久,开始没有思路,不知道如何做,然后偷偷看了一下别人的提示,说用dp[l][r][lc][rc]四维的数组来记录状态,于是就按这个思路,想了种方案,以为是那种很简单的dp,但是实际敲起来却发现各种都没考虑到。

这题的重点是一个串可能由多个匹配括号并列的,而且判断染色时得用到旁边的两个括号,递归时不好处理...

开始我没考虑到多个匹配括号并列,以为直接跟之前的dp题一样做就行了,结果跪了...现在看来这种想法够幼稚,这样只能判断((()))这样的括号串...

后来越来越想得用两个函数互相调用进行递归,但是处理状态记录想得头都大了...敲了好几个版本都跪了...

没办法了,看别人博客也没讲思路,瞥了一眼代码,看到了dfs的函数名,豁然开朗啊。。并确定一下人家只用了一个函数进行递归,于是我开始考虑把两个函数写在一块。

于是,不扯了,一下是思路:

先每对对括号进行记录。

dp的时候,当左右两边括号是匹配的时候,就为两个括号染色,然后就把状态转移到它们里面的括号串了

当不匹配的时候,也就是这个串是由多个匹配串并列而成的,那么就是dfs的思想了,为第一对括号染色,并求这对括号的子括号串的染色方案数,然后dp后面的那些串,直到dp到只剩一个串,并根据乘法原则把各种方案累计起来。(这样做是因为染色是和两边的括号颜色有关系的,而我们在dp前必须确定这个串两端的括号颜色。

递归的停止是当括号只有两个时,返回可能的染色数。

由于变量声明位置不对,结果wa了好几次,真是逗比...

代码:

#include <cstdio>
#include <cstring>

typedef long long LL;

const int MAXN = 710;
const LL MOD = 1e9 + 7;

char str[MAXN];
int color[MAXN];
int w[4][2] = {{1, 0}, {0, 1}, {2, 0}, {0, 2}};
// 0: 无色
// 1: 红
// 2: 蓝
int f[MAXN][MAXN][4][4], match[MAXN];
int stk[MAXN], cnt;

int dp(int l, int r) {
	LL sum = 0, pre, els;
	if (l == r - 1) {
		// check
		if (color[l - 1] != 1) sum++;
		if (color[l - 1] != 2) sum++;
		if (color[r + 1] != 1) sum++;
		if (color[r + 1] != 2) sum++;
		return sum;
	}
	if (match[l] == r) {
		for (int i = 0; i < 4; i++) {
			if (color[l - 1] == w[i][0] && w[i][0]) continue;
			if (color[r + 1] == w[i][1] && w[i][1]) continue;
			// dfs dp(l + 1, r - 1)
			color[l] = w[i][0];
			color[r] = w[i][1];
			if (!f[l + 1][r - 1][w[i][0]][w[i][1]])
				f[l + 1][r - 1][w[i][0]][w[i][1]] = dp(l + 1, r - 1);
			sum += f[l + 1][r - 1][w[i][0]][w[i][1]];
			sum %= MOD;
		}
	} else {
		// make sure of the first (*) and dfs the else
		for (int i = 0; i < 4; i++) {
			if (color[l - 1] == w[i][0] && w[i][0]) continue;
			// color first ()
			color[l] = w[i][0];
			color[match[l]] = w[i][1];
			// pre = dp(l, match[l])
			if (l == match[l] - 1)
				pre = 1;
			else {
				if (!f[l + 1][match[l] - 1][w[i][0]][w[i][1]])
					f[l + 1][match[l] - 1][w[i][0]][w[i][1]] = dp(l + 1, match[l] - 1);
				pre = f[l + 1][match[l] - 1][w[i][0]][w[i][1]];
			}
			// els = dp(match[l] + 1, r)
			if (!f[match[l] + 1][r][color[match[l]]][color[r + 1]])
				f[match[l] + 1][r][color[match[l]]][color[r + 1]] = dp(match[l] + 1, r);
			els = f[match[l] + 1][r][color[match[l]]][color[r + 1]];
			// ans = pre * els
			sum += pre * els;
			sum %= MOD;
		}
	}
	return sum;
}

int main() {
	gets(str + 1);
	int len = strlen(str + 1);
	// 预处理
	for (int i = len; i >= 1; i--)
		if (str[i] == ')') stk[cnt++] = i;
		else match[i] = stk[--cnt];
	printf("%d\n", dp(1, len));
	return 0;
}


几天做出一道这种题目,真是心情舒畅啊。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: