hdu 4489 The King’s Ups and Downs (组合数学 + dp )

           题目链接:点击打开链接

            题意:给了你n名不同身高的士兵,求有多少种方法是把他们按波浪状(高低高或低高低)排列。

           既然是要按波浪状排列,而且士兵的身高有各不相同,那么我们可以枚举枚举身高最高(或最低)的士兵所在的位置,左边肯定    .... 低高低,右边肯定是低高低  .... 。

    如 集合{1,2,3,4,5},当5在第4个位置是,左边有三个数,右边有一个数,这四个数左右分配的方法数就是C(4 , 1 )  或C(4,3) ,右边这种情况下就只有1个数,没啥好说的,左边3个数,而且是以低结尾的,我们用dp[3][0]表示,我们可以用同样的方法递归求出。

           在求解时最后一个数字可以是高,也可能是低,即答案=dp[n][0]+dp[n][1],其实枚举出最高士兵位置后,如果右边人数为偶数时这个序列以高结尾,即dp[n][1],奇数相反,为dp[n][0]。

         而且在递归求解过程中要求解大量重复的dp[i][0],dp[i][1],我们只要从小开始求,就可以避免重复求解,其实这也算是记忆化吧。

      具体详见代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
LL dp[30][2];
LL C(int a,int b)//组合数学,求C(a,b)
{
	LL fm=1,fz=1;
	for(int i=0;i<b;i++)
	{
		fm*=(b-i);
		fz*=(a-i);
	}
	return fz/fm;
}
void init()
{
	int i,j;
	dp[0][0]=1;
	dp[0][1]=1;
	dp[1][1]=1;
	dp[1][0]=1;
	dp[2][1]=1;
	dp[2][0]=1;
	for(i=3;i<=20;i++)
	{
		dp[i][0]=0; dp[i][1]=0;
		for(j=1;j<=i;j++)
		{
			int l=j-1;
			int r=i-j;
			LL ans=C(i-1,l);
			ans=ans*dp[l][0]*dp[r][0];
			if(r&1) dp[i][1]+=ans;
			else dp[i][0]+=ans;
		//	cout<<ans<<endl;
		}
		//cout<<dp[i][0]+dp[i][1]<<endl<<endl;
	}
	
}
int main()
{
	init();
	int n,m;
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		LL ans=dp[m][1]+dp[m][0];
		if(m==1) ans=1;
		printf("%d %lld\n",n,ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值