HDU 2068 RPG的错排(错排公式),详解

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2068

这题用到了错排公式和排列组合的知识。

关于排列组合的内容我就不讲了,原谅我比较懒吧,真不会可以选择百度

什么是错排呢,错排就是n个人全都不在自己位置上的所有排列方法,或者说就是n个人完全排错的方法

1的错排数就是只有一个人,一个位置,不管怎么站,他永远都只能在自己的位置上,所以1的错排数为0;2的错排就是两个人都不在自己位置上,只有一种,所以2的错排数为1;3之后的自己慢慢画就清楚了。

递推错排公式:将n个人的错排数记为f[n]。将n中的第1个排错,假设放在第k个位置(k不在第一个,不然就不是错排了),有n-1种放法。那么第k个人若放在第1个位置,剩下的还有n-2个进行错排,为f[n-2];若第k个人不放在第1个位置,则还有n-1个需要错排,为f[n-1]。因此得到错排数公式:f[n]=(n-1)*(f[n-1]+f[n-2]),其中f[0]=0.f[1]=0,f[2]=1。

在本题中女生们只要求他答对一半或以上就算过关,所以错排j从0依次到n/2即可,j的错排数乘上n个选j个的组合数就是n个有j个排错的所有可能,最后累加就好了。下面是代码,有问题欢迎指出。

#include
#include
using namespace std;
long long int res[30] = {0, 1, 1, 1};//最终结果
long long int b[15] = {1,0,1};//错排数
long long int factor[15] = {1, 1, 2, 6};//阶乘
long long int combination(int n, int m)//求 m 个中选 n 个的组合数
{
	int minn = min (m - n, n);//m - n 和 n 较小的一个
	long long int sum = 1;
	//我怕 25 的阶乘太大,所以先算出来 25 的阶乘和两者中较大者的阶乘相除的结果
	for (int i = 0; i < minn; i++)
	{
		sum *= (m - i);
	}
	sum /= factor[minn];
	return sum;
}
void add()//求最终结果
{
	for (int i = 3; i < 14; i++)
	{
		b[i] = (i - 1) * (b[i - 1] + b[i - 2]);//错排数
		factor[i] = factor[i - 1] * i;//阶乘
	}
	for (int i = 4; i < 26; i++)
	{
		int j = i / 2;
		long long int sum = 1;
		for (int k = 2; k <= j; k++)
		{
			sum += combination(k, i) * b[k];
		}
		res[i] = sum;
	}
	return;
}
int main()
{
	add();
	int n;
	while (cin >> n, n)
	{
		cout << res[n] << endl;
	}
	//喜欢C语言的朋友可以用下面这种,
	/*
    while (scanf ("%d", &n)!=EOF)
    {
    	if (n == 0)
			break;
		printf("%lld\n", res[n]);
	}
	*/
	return 0;
}

你可能感兴趣的:(杭电水题)