POJ 1187 陨石的秘密 ()[]{}帯权dp

题意:给定()[]{}的数量分别为l1,l2,l3(0<=l1,l2,l3<=10),规定()不能套在[]和{}的外面,[]不能套在{}的外面,即{} [] ()优先级递减,现在想最大组成嵌套深度为d
        (0<=d<=30)的串,问一共有多少种方法。

题解:首先很容易想到记忆化dfs,dp[a][b][c][d]表示{}[]()分别有a b c个形成最大嵌套深度为d的方法数,然后找到子状态,但是麻烦的是d是多个子问题求max得到的,这样
         在dfs的过程中没办法控制哪一个是最大的,看了下提示瞬间石化。
         dp[a][b][c][d]表示{}[]()分别有a b c个形成最大嵌套深度小于等于d的方法数,这样能得到子状态,由于优先级的问题改变遍历{}[]()的顺序即可,枚举当前在左边套在最
         外面的是{}[]或(),最后得到答案为dp[a][b][c][d] – dp[a][b][c][d-1](d == 0时候答案为dp[a][b][c][d])。因为dfs时分开的两个串是独立的,所以不会有重复计数。

PS:网上有一个想法说的很好:把括号的嵌套看成是一棵树就简单些,这棵树的最大深度为 D,()节点下面不能有{}[]节点,[]节点下面不能有{}节点,然后从上往下
       依次摆放节点。

Sure原创,转载请注明出处。

#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
const int maxn = 12;
const int maxm = 32;
const int mod = 11380;
int dp[maxn][maxn][maxn][maxm];
bool vis[maxn][maxn][maxn][maxm];
int a,b,c,d;

int dfs(int l1,int l2,int l3,int dep)
{
    if(l1 == 0 && l2 == 0 && l3 == 0)
    {
        vis[l1][l2][l3][dep] = true;
        return dp[l1][l2][l3][dep] = 1;
    }
    if(dep == 0)
    {
        vis[l1][l2][l3][dep] = true;
        return dp[l1][l2][l3][dep] = 0;
    }
    if(vis[l1][l2][l3][dep])
    {
        return dp[l1][l2][l3][dep];
    }
    int res = 0;
    for(int i=0;i<=l3;i++)
    {
        if(i)
        {
            res += (dfs(0,0,i-1,dep-1) * dfs(l1,l2,l3-i,dep)) % mod;
            res %= mod;
        }
        for(int j=0;j<=l2;j++)
        {
            if(j)
            {
                res += (dfs(0,j-1,i,dep-1) * dfs(l1,l2-j,l3-i,dep)) % mod;
                res %= mod;
            }
            for(int k=1;k<=l1;k++)
            {
                res += (dfs(k-1,j,i,dep-1) * dfs(l1-k,l2-j,l3-i,dep)) % mod;
                res %= mod;
            }
        }
    }
    vis[l1][l2][l3][dep] = true;
    return dp[l1][l2][l3][dep] = res;
}

int main()
{
    memset(vis,false,sizeof(vis));
    while(~scanf("%d %d %d %d",&a,&b,&c,&d))
    {
        dfs(a,b,c,d);
        if(d) dfs(a,b,c,d-1);
        int ans;
        if(d == 0) ans = dp[a][b][c][d];
        else ans = ((dp[a][b][c][d] - dp[a][b][c][d-1]) % mod + mod) % mod;
        printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(POJ 1187 陨石的秘密 ()[]{}帯权dp)