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

本文介绍了一种使用组合动态规划解决特定排列问题的方法。针对给定数量的不同身高的人,求解他们能以高矮交替方式排列的所有可能方案数。通过对称性简化问题并采用递归方法计算组合数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

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;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值