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

题目连接: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
#include
#define LL long long

LL 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;
}



你可能感兴趣的:(DP)