题意:
给一个给定括号序列,给该括号上色,上色有三个要求
1、只有三种上色方案,不上色,上红色,上蓝色
2、每对括号必须只能给其中的一个上色
3、相邻的两个不能上同色,可以都不上色
求0-len-1这一区间内有多少种上色方案
思路:括号匹配问题是典型区间dp问题,这题在此基础上改编增加颜色的规定,于是我需要多定义两层设dp[i][j][l][r]表示:从i到j这个括号序列i位置为l颜色,j位置为r颜色的状态下的总共上色方案。可以规定0为不上色,1为红色,2为蓝色,这样dp[len][len][3][3]状态就定好了。
考虑括号串的匹配过程,都是嵌套的过程,于是我们可以递归的计数,首先得用栈扫一遍串,记载每个左右括号相对的匹配的位置。然后递归的搜索下去。
根据题意的规则,制定搜索的规则。
详见代码:
#include<bits/stdc++.h>
using namespace std;
char s[700+10];
const int mod=1e9+7;
int match[700+10],n;
long long dp[700+10][700+10][3][3];
stack<int>sta;
void init(){
while(!sta.empty()) sta.pop();
for(int i=1;i<=n;i++){
if(s[i]=='(') sta.push(i);
else { match[i]=sta.top();match[sta.top()]=i;sta.pop();}
}
}
void dfs(int l,int r){
if(l+1==r){
dp[l][r][1][0]=1;dp[l][r][0][1]=1;//每一对括号只有有且只有一个括号有颜色的情况计数,其他为0
dp[l][r][2][0]=1;dp[l][r][0][2]=1;
return;
}
if(match[l]==r){
dfs(l+1,r-1);
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
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;
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;
}
}
}
else{
int p=match[l];
dfs(l,p);dfs(p+1,r);
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
for(int q=0;q<3;q++){
if(k!=q||k==0) dp[l][r][i][j]=(dp[l][r][i][j]+dp[l][p][i][k]*dp[p+1][r][q][j])%mod;//保证相邻的不同颜色,或者都不上色
}
}
}
}
}
}
int main(){
while(~scanf("%s",s+1)){
n=strlen(s+1);
init();
memset(dp,0,sizeof(dp));
dfs(1,n);
long long ans=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
ans=(ans+dp[1][n][i][j])%mod;
}
}
printf("%lld\n",ans);
}
}