开始我的思路是:固定一半,另一半用组合公式cn1+cn2+cn3+cn4+.....+cni;最后用全排列减去它们即可。最后发现思路完全不对,必须用错排公式进行计算。即Cnm*a[N-m]; 从N个人中选出m个正确的,用错排公式算出(N-m)没在对应位置的个数。根据分步计数原理,可以得到结果。

CODE:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
using namespace std;

int a[21];

double PaC(int n, int m)                   //Permutation and combination.
{
    double s = 1, i;   //小技巧,doulbe型的定义 
    for(i = 0; i < m ; i++)
        s *= (n-i)/(i+1);
         return s;
}


void init()                           //错排的序列 
{
    int i;
    a[0] = 0; a[1] = 0; a[2] = 1;
    for(int i = 3; i <= 21; i++)
    {
        a[i] = (a[i-1]+a[i-2])*(i-1);
    }
    return ;
}

int main()
{
    int N;
    int i;
    double sum;
    init();
    while(~scanf("%d", &N), N)
    {
        int m;
        sum = 0;
        if(N%2 == 0)
        {
            m = N/2;
        }
        else
        {
            m = N/2+1;
        }
        for(i = m; i < N; i++)
        {
            sum += PaC(N, i)*a[N-i];            //Cnm*a[N-m];即从中选出m个正确的,则有n-m个错排的。根据分步计数原理可知。 
        }
        printf("%.lf\n", sum+1);
    }
    return 0;

} 

posted on 2012-07-11 16:24  有间博客  阅读(798)  评论(0编辑  收藏  举报