CF149D Coloring brackets(区间dp)
题目链接CF149D
括号染色问题,经典区间dp。
题目
大意就是给你一串正确的括号序列(每个括号都有与他唯一的匹配),
问按照如下的规则进行染色:
1)每个括号要么被染成红色、蓝色,或者不染色。
2)对于每一对相互匹配的括号只能对其中的一个括号染色。
3)相邻的两个括号不能被染成相同的颜色(但是可以都不染色)。
问你有多少种染色方案,注意第3)个,相邻的两个括号可以都不染色,这点不能忽略。。。。
思路
- 首先我们肯定需要找到每个与左括号匹配的右括号,建立关系。
- dp,这个最好用记忆搜索来实现,因为状态很多。 需要哪些状态呢?首先肯定需要 ( i , j ) (i,j) (i,j)这两个参数代表序列左端和右端下标,那么根据题目,我们对其染色必须要满足一些条件,所以考虑加入 ( l , r ) (l,r) (l,r)分别代表第 i − 1 i-1 i−1个括号和第 j + 1 j+1 j+1个括号的颜色,有了这两个状态我们就可以确定如何对第 i i i个括号和第 j j j个括号染色了。我们另R(1)代表红色,B(2)代表蓝色,(0)代表不染色。则每一对匹配的括号只有这四种情况: ( 0 , R ) , ( R , 0 ) , ( 0 , B ) , ( B , 0 ) (0,R),(R,0),(0,B),(B,0) (0,R),(R,0),(0,B),(B,0)。
- 如果 i i i与 j j j的括号是匹配的,那么子问题就是 ( i + 1 , j − 1 ) (i+1,j-1) (i+1,j−1),如果不匹配,我们就要把序列分成两部分, 令 m = m a t c h [ i ] 令m=match[i] 令m=match[i], 那么子问题就是 ( i + 1 , m − 1 ) (i+1, m-1) (i+1,m−1)与 ( m + 1 , j ) (m+1, j) (m+1,j)
代码:
注意会爆int,用longlong
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
typedef long long ll;
const int mod = 1000000007;
const int R = 1; // 红
const int B = 2; // 蓝
int n;
char Bra[710];
int match[710];
ll dp[710][710][5][5];
stack<int> st;
void getMatch() {
//得到括号之间的匹配关系。
for (int i = 0; i < n; i++) {
if (Bra[i] == '(') st.push(i);
else {
int s = st.top();
match[s] = i;
st.pop();
}
}
}
ll dfs(int i, int j, int l, int r) {
ll res = 0;
if (i >= j) return 1;
if (dp[i][j][l][r] != -1) return dp[i][j][l][r];
if (match[i] == j) {
//两端括号匹配的情况
if (l != R ) res += dfs(i+1, j-1, R, 0) % mod;
if (r != R ) res += dfs(i+1, j-1, 0, R) % mod;
if (l != B ) res += dfs(i+1, j-1, B, 0) % mod;
if (r != B ) res += dfs(i+1, j-1, 0, B) % mod;
}
else {
//两端括号不匹配,把序列分成两段。因为两段独立,所以染色数为两段染色数的乘积。
int m = match[i];
if (l != R) res += (dfs(i+1, m-1, R, 0) * dfs(m+1, j, 0, r)) % mod;
if (l != B) res += (dfs(i+1, m-1, B, 0) * dfs(m+1, j, 0, r)) % mod;
res += (dfs(i+1, m-1, 0, R) * dfs(m+1, j, R, r)) % mod;
res += (dfs(i+1, m-1, 0, B) * dfs(m+1, j, B, r)) % mod;
}
dp[i][j][l][r] = res % mod;
return res;
}
void solve() {
getMatch();
memset(dp, -1, sizeof(dp));
//初始时两边并没有括号,但是假定两边括号颜色是3就没有问题。
ll res = dfs(0, n-1, 3, 3);
cout << res % mod << endl;
}
int main() {
cin >> Bra;
n = strlen(Bra);
solve();
return 0;
}