您的位置:首页 > 其它

hdu4489 dp+递推

2016-01-20 16:54 405 查看
题意:

有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个位置得到的种数和。其中我们注意到,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
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: