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

来源:互联网 发布:java使用ftp上传文件 编辑:程序博客网 时间:2024/05/19 15:21

           题目链接:点击打开链接

            题意:给了你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