首页 > 代码库 > HDU 5151Sit sit sit

HDU 5151Sit sit sit

一道区间DP题,某次BestCoder的B题,想了很久没想出来。

题目描述:一共有并排N个椅子, N个学生依次去坐,同时满足3个条件就不能坐下去:1,该椅子不在最左,不在最右,2,该椅子左右都有人坐了,3,左右的椅子不同颜色
求最后N个人都能坐下去,有多少不同的情况.

题解:dp[i][j]表示排完区间[i,j]的种类数,(看别人题解时没想明白,人是按顺序先后决定坐的位置,即在区间[i,j]内座位的先后序。当[i,j]->[1,n]时,dp的种类数不就是n个人按顺序先后决定坐的位置的种类

转移方程:  dp[i][j] = SUM ( dp[i][k-1]*dp[k+1][j]* C[j-i][i-k] )        其中v[k-1]==v[k+1],保证最后的那个最为合法。乘以组合数的原因是在j-i个人中决定坐前一个区间的人(选完之后,他们是有序的)。

代码君:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
const int N = 100+10;
const int mod = 1e9+7;
typedef long long ll;
ll dp[N][N];
int a[N];
ll C[N][N];
void init()
{
    for(int i=0;i<=100;i++) C[i][0] = 1;
    for(int i=1;i<=100;i++)
        for(int j=1;j<=i;j++)
            C[i][j] =( C[i-1][j-1] + C[i-1][j] )%mod;
}
ll dfs(int i,int j)
{
    if(i>j) return 0;
    if(i==j) return dp[i][j]=1;
    if(dp[i][j]!=-1) return dp[i][j];
    ll ans = 0;
    ans =( dfs(i+1,j) + dfs(i,j-1) )%mod;
    for(int k=i+1;k<=j-1;k++)
    {
        if(a[k-1]!=a[k+1]) continue;
        ans = ( ans + dfs(i,k-1)*dfs(k+1,j)%mod*C[j-i][k-i]%mod)%mod;
    }
    return dp[i][j] = ans;
}
int main()
{
    int n;
    init();
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        memset(dp,-1,sizeof(dp));
        ll ans = dfs(1,n);
        printf("%lld\n",ans);
    }
    return 0;
}



HDU 5151Sit sit sit