codeforces 149d 区间dp + 记忆化搜索

题意:

只包括'(' , ')'的长度为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) ;
}

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/88054390