hdu4489 dp+递推

题意:

有n个高矮不同的士兵,现在要将他们按高,矮依次排列,问有多少种情况。

分析:

组合dp问题。

假设n个士兵的身高分别为1,2......n。

我们现在考虑n个士兵的情况,最后一个身高为n的最高的士兵应该站在哪里呢。我们可以看到前面有n-1个士兵,一共有n个位置可以站,但是我们注意到要按高矮的顺序排列。因为n的身高最高,所以他插入的位置前面一个人应该是按照下降得到的,后面一个人应该是按照上升得到的。

假设dp[i][0]表示的是有i个人,并且第二个人比第一个人高的情况,dp[i][1]表示的是有i个人,并且最后一个人比倒数第二个人矮的情况,士兵n插入位置为前面有i个人,后面有n-1-i个人,这时的情况种数应该为:dp[i][1]*dp[n-1-i][0]*C(n-1,i),最后乘以组合数的原因是在n-1个人中选出i个人的种数。这是要计算的总的情况数sum[n] 就等于将n依次插入n个位置得到的种数和。其中我们注意到,dp[i][0] = dp[i][1] = sum[i]/2.


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

#define LL long long
const int maxn = 25;

LL dp[maxn][2];
//dp[i][0]表示的是有i个人,并且第二个人比第一个人高的情况
//dp[i][1]表示的是有i个人,并且最后一个人比倒数第二个人矮的情况
LL sum[maxn];

LL cal(int a,int b)
{
    if(b==0)return 1;
    LL ans = 1 ;
    b = min(b,a-b);
    for(int i = 1 ; i <= b ; i++)
    {
        ans*=(a-i+1);
        ans/=i;
    }
    //cout<<ans<<endl;
    return ans;
}

void call()
{
    memset(dp,0,sizeof(dp));
    memset(sum,0,sizeof(sum));
    sum[1] = 1 ; //初始化
    sum[2] = 2 ;
    dp[0][0] = dp[0][1] = 1 ;
    dp[1][0] = dp[1][1] = 1 ;
    dp[2][0] = dp[2][1] = 1 ;
    for(int i = 3 ; i <= 20 ; i++)
    {
        for(int j = 0 ; j < i ; j++)
        {
            sum[i]+=dp[j][0]*dp[i-1-j][1]*cal(i-1,j);
            //cout<<sum[i]<<endl;
        }
        //cout<<sum[i]<<endl;
        dp[i][0] = dp[i][1] = sum[i]/2;
    }
}

int main()
{
    call();
    int t,n,d;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&d,&n);
        printf("%d %I64d\n",d,sum[n]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值