组合dp hdu-4489-The King’s Ups and Downs

来源:互联网 发布:最新网络理财产品 编辑:程序博客网 时间:2024/05/06 19:18

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4489

题目意思:

给一个n,求n个高矮不同的人排成一排使得高、矮依次排列的种数。

解题思路:

组合dp.

对于n个人,设其高度分别为1,2,3,,,,,n.  

对于第n个人,假设前面的n-1个人已经放好了。第n个人有n个位置可放,对于任一位置j,显然第n个人的身高n大于前n-1个人的任何人的身高。所以第n个人左边的j-1个人的排列

中,必须满足最后一个人一定是通过身高下降得到的,右边的n-j个人中,最开始的那个人一定通过升高得到后面一个人的,当然前面j-1个人可选C(n-1,j-1)。

所以设状态dp[i][0]表示有i个人,并且第一个人通过上升得到第二个人的总的排列种数,i个人身高肯定不一样,故只考虑个数。

dp[i][1]表示有i个人,并且最后一个人是通过下降得到的。

很显然在人数相同的情况下,由对称性得 dp[i][0]=dp[i][1]=sum[i]/2 sum[i]为i个人总的满足要求的排列数。

对于第n个人放到位置j ,有C(n-1,j-1)*dp[j-1][0]*dp[n-j][1]种情况。

代码:

#include <iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<cstdlib>#include<cctype>#include<map>#include<set>#include<queue>#include<vector>using namespace std;const double eps = 1e-5;const double PI = acos(-1.0);typedef __int64 ll;ll dp[30][2];ll sum[30];ll Cal(int a,int b) //求出Cab 其实可以用递推来算的,Cab=C(a-1)(b-1)+C(a-1)b{    if(b==0)        return 1;    ll res=1;    for(int i=0;i<b;i++)    {        res*=(a-i);    }    for(int i=1;i<=b;i++)        res/=i;    return res;}int main(){    dp[0][0]=dp[0][1]=1;    dp[1][0]=dp[1][1]=1;    sum[1]=1;    for(int i=2;i<=20;i++)    {        sum[i]=0;        for(int j=1;j<=i;j++)        {            sum[i]+=(dp[j-1][0]*dp[i-j][1]*Cal(i-1,j-1));        }        dp[i][0]=dp[i][1]=sum[i]/2;//由对称性        //printf("i:%d %I64d \n",i,sum[i]);    }   // printf("%d %I64d\n",20,sum[20]);    int t;    int d,k;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&d,&k);        printf("%d %I64d\n",d,sum[k]);    }    return 0;}