动态规划训练10 [Coloring Brackets CodeForces

来源:互联网 发布:发货后淘宝店铺不存在 编辑:程序博客网 时间:2024/06/04 19:24

西安交大 软件53 蔡少斐 整理

Coloring Brackets

 CodeForces - 149D 


题目大意:

给定合法的括号序列,让你给括弧上色,并且上色时一定要满足3个要求:

(1)每个括号要么被上红色,要么被上蓝色,要么不上色。

(2)一对匹配的左右括弧,有且只有其中的一个可以被上色。

(3)相邻的括弧不能被涂上相同的颜色。


这道题也是很明显的区间DP问题,遗憾的是,我一开始没有想到怎么dp。


首先我们要进行预处理,求出每个括号的唯一配对的括号,即寻找他们一一对应的关系,这个预处理很简单,用栈操作一下就可以了

预处理代码:

gets(str);stack<int> stk;int len = strlen(str);for(int i = 0;i < len;i++){if(str[i] == '('){stk.push(i);}else{int p = stk.top();stk.pop();mp[p] = i;mp[i] = p;}}

下面我们考虑的区间,全部都是配对合法的区间!

用一个四维数组dp[l][r][i][j]表示区间[l,r]且l处被涂上i色,r处被涂上j色。(规定无色为0,红色为1,蓝色为2)

那么我们可以得到下面的状态转移方程:

(1)当区间长度只有2时候(两个括弧一定是配对的,因为我们考虑的所有区间都是配对合法的区间),上色方案是非常好确定的。

dp[l][r][0][1] = 1;
dp[l][r][0][2] = 1;
dp[l][r][1][0] = 1;
dp[l][r][2][0] = 1;

(2)当区间的左右括弧是配对的时候(判断左右括弧是否匹配,用到了预处理得到的结果)。则有如下转移方法:

if(j != 1)
dp[l][r][0][1] = (dp[l][r][0][1] + dp[l+1][r-1][i][j])%MOD;
if(j != 2)
dp[l][r][0][2] = (dp[l][r][0][2] + dp[l+1][r-1][i][j])%MOD;
if(i != 1)
dp[l][r][1][0] = (dp[l][r][1][0] + dp[l+1][r-1][i][j])%MOD;
if(i != 2)
dp[l][r][2][0] = (dp[l][r][2][0] + dp[l+1][r-1][i][j])%MOD;

(3)当区间非左右配对时,把区间划分为左右两个各自合法 的区间,转移方程是。

dp[l][r][i][j] = (dp[l][r][i][j] + dp[l][k][i][p] * dp[k+1][r][q][j]%MOD)%MOD;

这里注意k代表的是与l配对的括号,那么k+1就是与r配对的括号了。(这就是预处理的作用!)


而在动态规划的实现过程中,我们发现并非所有的区间都是合法的,只有少部分的区间是合法的,因此我们用自顶向下的记忆化dp的方法,这样可以简化代码的实现。


代码:

#include <iostream>#include <cstdio>#include <cstring>#include <stack>#include <algorithm>#define int long long using namespace std;const int MAX = 705;const int MOD = 1e9 + 7;int used[MAX][MAX];int mp[MAX];char str[MAX];int dp[MAX][MAX][3][3];void dfs(int l,int r){if(used[l][r]) return ;used[l][r] = 1;if(l + 1 == r){dp[l][r][0][1] = 1;dp[l][r][0][2] = 1;dp[l][r][1][0] = 1;dp[l][r][2][0] = 1;return ;}if(mp[l] == r){//配对的情况 dfs(l+1,r-1);for(int i = 0;i < 3;i++){for(int j = 0;j < 3;j++){if(j != 1)dp[l][r][0][1] = (dp[l][r][0][1] + dp[l+1][r-1][i][j])%MOD;if(j != 2)dp[l][r][0][2] = (dp[l][r][0][2] + dp[l+1][r-1][i][j])%MOD;if(i != 1)dp[l][r][1][0] = (dp[l][r][1][0] + dp[l+1][r-1][i][j])%MOD;if(i != 2)dp[l][r][2][0] = (dp[l][r][2][0] + dp[l+1][r-1][i][j])%MOD;}}}else{int k = mp[l];dfs(l,k);dfs(k+1,r);for(int i = 0;i < 3;i++){for(int j = 0;j < 3;j++){for(int p = 0;p < 3;p++){for(int q = 0;q < 3;q++){if(p + q == 0 || p != q ){dp[l][r][i][j] = (dp[l][r][i][j] + dp[l][k][i][p] * dp[k+1][r][q][j]%MOD)%MOD;}}} }}  }}main(){gets(str);stack<int> stk;int len = strlen(str);for(int i = 0;i < len;i++){if(str[i] == '('){stk.push(i);}else{int p = stk.top();stk.pop();mp[p] = i;mp[i] = p;}}dfs(0,len-1);int ans = 0;for(int i = 0;i < 3;i++){for(int j = 0;j < 3;j++){ans = (ans + dp[0][len-1][i][j])%MOD;}}cout<<ans<<endl;return 0;} 


阅读全文
0 0