开始我的思路是:固定一半,另一半用组合公式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;
#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;
}