动态规划训练10 [Coloring Brackets CodeForces - 149D]
Coloring Brackets
?CodeForces - 149D?
題目大意:
給定合法的括號(hào)序列,讓你給括弧上色,并且上色時(shí)一定要滿足3個(gè)要求:
(1)每個(gè)括號(hào)要么被上紅色,要么被上藍(lán)色,要么不上色。
(2)一對(duì)匹配的左右括弧,有且只有其中的一個(gè)可以被上色。
(3)相鄰的括弧不能被涂上相同的顏色。
這道題也是很明顯的區(qū)間DP問題,遺憾的是,我一開始沒有想到怎么dp。
首先我們要進(jìn)行預(yù)處理,求出每個(gè)括號(hào)的唯一配對(duì)的括號(hào),即尋找他們一一對(duì)應(yīng)的關(guān)系,這個(gè)預(yù)處理很簡單,用棧操作一下就可以了
預(yù)處理代碼:
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;}}下面我們考慮的區(qū)間,全部都是配對(duì)合法的區(qū)間!
用一個(gè)四維數(shù)組dp[l][r][i][j]表示區(qū)間[l,r]且l處被涂上i色,r處被涂上j色。(規(guī)定無色為0,紅色為1,藍(lán)色為2)
那么我們可以得到下面的狀態(tài)轉(zhuǎn)移方程:
(1)當(dāng)區(qū)間長度只有2時(shí)候(兩個(gè)括弧一定是配對(duì)的,因?yàn)槲覀兛紤]的所有區(qū)間都是配對(duì)合法的區(qū)間),上色方案是非常好確定的。
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)當(dāng)區(qū)間的左右括弧是配對(duì)的時(shí)候(判斷左右括弧是否匹配,用到了預(yù)處理得到的結(jié)果)。則有如下轉(zhuǎn)移方法:
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)當(dāng)區(qū)間非左右配對(duì)時(shí),把區(qū)間劃分為左右兩個(gè)各自合法 的區(qū)間,轉(zhuǎn)移方程是。
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配對(duì)的括號(hào),那么k+1就是與r配對(duì)的括號(hào)了。(這就是預(yù)處理的作用!)
而在動(dòng)態(tài)規(guī)劃的實(shí)現(xiàn)過程中,我們發(fā)現(xiàn)并非所有的區(qū)間都是合法的,只有少部分的區(qū)間是合法的,因此我們用自頂向下的記憶化dp的方法,這樣可以簡化代碼的實(shí)現(xiàn)。
代碼:
#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){//配對(duì)的情況 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; }創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔為你收集整理的动态规划训练10 [Coloring Brackets CodeForces - 149D]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 特斯拉加速扩张,年产能达235万辆
- 下一篇: 动态规划训练11 [String pai