1. 程式人生 > >hdu2068 錯排公式

hdu2068 錯排公式

一個有n個元素的排列,若一個排列中所有的元素都不在自己原來的位置上,那麼這樣的排列就稱為原排列的一個錯排,n個元素的錯排數記為D(n)。那麼對於這樣的排列D(n)有多少種呢?我們一步一步進行分析:

  首先,對於D(n),有1~n這樣n個元素錯排,所以對於第一個元素①,它現在可能的位置有(n-1)個,倘若它在第k個元素的位置上,對於第k個元素而言,它所在的位置就有兩種可能:第一種,它處在非第一個元素①位置上,所以對於接下來的排列就相當於是n-1個元素的錯排,即D(n-1);第二種,它處在第一個元素①的位置上,所以在排列D(n)中有兩個元素找到了位置,那麼接下來的佇列就相當於是n-2個元素的錯排。因此,對於D(n)都有D(n)=(n-1)*(D(n-1)+D(n-2))   特殊的,D(1)=0,D(2)=1。
 

Problem Description

今年暑假杭電ACM集訓隊第一次組成女生隊,其中有一隊叫RPG,但竟然不知道RPG的n個人具體是誰誰。RPG給他機會讓他猜猜,......女生們只要求他答對一半或以上就算過關,請問有多少組答案能使他順利過關。

Input

輸入的資料裡有多個case,每個case包括一個n,代表有幾個女生,(n<=25), n = 0輸入結束。

Sample Input

1 2 0

Sample Output

1 1

#include "pch.h"
#pragma warning (disable:4996)
#include<stdio.h>
#include <iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
long long comb[100][100];
long long wcomb[100];

long long com(int a, int b) {
	if (comb[a][b] >= 0) return comb[a][b];
	long long res;
	if (a == b || b == 0) return res = 1;
	else res = com(a - 1, b) + com(a - 1, b - 1);
	return comb[a][b] = res;
}
long long wcom(int b) {
	if (b == 1) return wcomb[1] = 0;
	if (b == 2) return wcomb[2] = 1;
	long long res;
	wcomb[b] = (b - 1)*(wcom(b - 1) + wcom(b - 2));
	return wcomb[b];
}
int main()
{
	//freopen("datain.txt", "r", stdin);
	int a;
	while (~scanf("%d", &a)) {
		if (!a) break;
		memset(comb, -1, sizeof(comb));
		memset(wcomb, -1, sizeof(wcomb));
		long long sum = 1;//全部正確的情況:1

//要求至少猜對一半或以上,則允許錯排的個數為a/2
//小數部分抹去
//當女生有3個的時候,a/2=1,但是一個女生無法錯排
//錯排的最小數字應該是2
		for (int b = a / 2;b >= 2;b--) {
			//當然此處寫成b>=1也沒關係,因為wcom(1)==0;
			sum += com(a, b)*wcom(b);
		}
		cout << sum << endl;
	}
}