CF149D Coloring brackets(区间dp)

CF149D Coloring brackets(区间dp)

题目链接CF149D
括号染色问题,经典区间dp。

题目

在这里插入图片描述
大意就是给你一串正确的括号序列(每个括号都有与他唯一的匹配),
问按照如下的规则进行染色:
1)每个括号要么被染成红色、蓝色,或者不染色。
2)对于每一对相互匹配的括号只能对其中的一个括号染色。
3)相邻的两个括号不能被染成相同的颜色(但是可以都不染色)。

问你有多少种染色方案,注意第3)个,相邻的两个括号可以都不染色,这点不能忽略。。。。

思路

  1. 首先我们肯定需要找到每个与左括号匹配的右括号,建立关系。
  2. dp,这个最好用记忆搜索来实现,因为状态很多。 需要哪些状态呢?首先肯定需要 ( i , j ) (i,j) (i,j)这两个参数代表序列左端和右端下标,那么根据题目,我们对其染色必须要满足一些条件,所以考虑加入 ( l , r ) (l,r) (l,r)分别代表第 i − 1 i-1 i1个括号和第 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)
  3. 如果 i i i j j j的括号是匹配的,那么子问题就是 ( i + 1 , j − 1 ) (i+1,j-1) (i+1,j1),如果不匹配,我们就要把序列分成两部分, 令 m = m a t c h [ i ] 令m=match[i] m=match[i], 那么子问题就是 ( i + 1 , m − 1 ) (i+1, m-1) (i+1,m1) ( 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;
}

运行结果

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值