题意:
只包括'(' , ')'的长度为n的字符串s,该字符串符合括号匹配原则。现在想要将s涂色。要求如下:
1.每个括号可以不涂色、涂红色或涂蓝色。
2.每对匹配的括号有且仅有一个括号涂色。
3.相邻括号可以都不涂色,但不能涂成相同颜色。
题解:
1.dp可以使用记忆化搜索或自底向上递推。
2.第i个字符是'(',match[i]存储第i个字符的匹配字符下标。第i个字符是')',match[i] = i。
3.dp[i][j][c1][c2]表示将第i个字符染成了c1颜色,第j个字符染成了c2颜色后[i , j]的种类数。
4.计算[i , j]种类数时,若第i个字符和第j个字符匹配,那么加上(i , j)种类数。如果不匹配那么加上[i , match[i]] * [match[i] + 1 , j]的种类数。
5.为了避免重复搜索,需要用dp数组存储已经遍历过的状态!!!!!!
#include <bits/stdc++.h>
#define N 705
#define inf 0x3f3f3f3f
#define mod 1000000007
using namespace std;
int dp[N][N][3][3] ;
int match[N] ;
char s[N] ;
bool judge(int a , int b)
{
return a == 0 || b == 0 || a != b ;
}
//相邻括号不能同色
//配对括号只有一个颜色
long long dfs(int l , int r , int c1 , int c2)
{
int i , j ;
int k = match[l] ;
long long ans = 0 ;
if(dp[l][r][c1][c2] != -1)
return dp[l][r][c1][c2] ;
if(l > r || k == r && (c1 != 0 && c2 != 0 || c1 == 0 && c2 == 0))
return 0 ;
else if(l + 1 == r)
return 1 ;
else if(k == r)
{
for(i = 0 ; i < 3 ; i ++)
for(j = 0 ; j < 3 ; j ++)
if(judge(c1 , i) && judge(j , c2))
ans = (ans + dfs(l + 1 , r - 1 , i , j)) % mod ;
}
else if(k < r)
{
for(i = 0 ; i < 3 ; i ++)
for(j = 0 ; j < 3 ; j ++)
if(judge(i , j))
ans = (ans + dfs(l , k , c1 , i) * dfs(k + 1 , r , j , c2)) % mod ;
}
dp[l][r][c1][c2] = ans ;
return ans ;
}
int main()
{
int i , j ;
int len ;
long long ans = 0 ;
stack <int> s1 ;
scanf("%s" , s + 1) ;
len = strlen(s + 1) ;
for(i = 1 ; i <= len ; i ++)
if(s[i] == '(')
s1.push(i) ;
else
{
match[s1.top()] = i ;
match[i] = i ;
s1.pop() ;
}
memset(dp , -1 , sizeof(dp)) ;
for(i = 0 ; i < 3 ; i ++)
for(j = 0 ; j < 3 ; j ++)
ans = (ans + dfs(1 , len , i , j)) % mod ;
printf("%lld" , ans) ;
}