The King's Ups and Downs(dp问题)

来源:互联网 发布:比尔盖茨编程一小时 编辑:程序博客网 时间:2024/05/22 03:50

题目连接:https://icpcarchive.ecs.baylor.edu/external/61/6177.pdf

题目大意:给定n个人,身高从依次从1到n,就这n个人的排列(按照高低高...或者低高低...)的方案数。

解题思路:这种排列叫做:alternating permutations 或者 Extremal Permutations 。从网上看了一些解题报告,借鉴了一些。这道题是用DP来做,现在讨论已知n-1个人,就n个人的方案数。首先是把身高为n的人放入之前的n-1个人中,首先原则i(0<=i<=n-1)个人放在身高为n的人的前面,有C(n-1, i)中选择方法,前i个人的的排列方案数为dp[i]/2,(因为高低高...和低高低...的排列方案数是相同的,当i=1时要特判,因为i=1只有一个排列方案数),身高为n的人的后面有n-1-i个人,排列的方案数为dp[n-1-i]/2,然后把这三个数相乘即为n个人时的排列方案数。

之前一直不明白为什么要dp[i]/2,后来想明白了,因为n比任何的人的身高都要高,所以对于n前面的人的排列方式,靠近n的那两个人的身高必是“高低”的排列,n后面的人的排列方式同理。

代码:

#include<cstdio>#include<cstring>#define LL long longLL num[21];LL cal(LL n, LL m){    LL i, a, b, p;    if(n < m){i = m; m = n; n = i;}    p = 1;    a = n - m < m ? n - m : m;    b = n - m > m ? n - m : m;    for(i=1; i<=a; i++)        p += p * b / i;    return p;}void init(){    for(int i=5; i<=20; i++){        LL res = 0;        LL n = (LL)i;        for(int i=0; i<=n-1; i++){            res += cal(n-1, i) * (num[i] / 2) * (num[n-1-i] / 2);        }        num[i] = res;    }}int main(){    int p, th, n;    num[0] = 2;    num[1] = 2;  //当n=1的排列方案数应该为1,不过为了避免num[1]/2不为0,所以初始化为2    num[2] = 2;    num[3] = 4; num[4] = 10;    init();    scanf("%d", &p);    while(p--){        scanf("%d%d", &th, &n);        printf("%d ",th);        if(n == 1) printf("1\n");  //当n=1时进行特判        else printf("%lld\n", num[n]);    }    return 0;}



0 0
原创粉丝点击