HDU 2068 RPG的错排 排列组合
解题报告:
题目大意:有N个人和N个名字,要将他们一一对应,对应的规则是至少要有N/2是对了的,求这样一共有多少种对应的方法。
错排题,从0开始枚举到N/2,即表示有0个人的名字与人对应是错的、1个人的名字与本人的对应是错的、两个人的名字与本人的对应是错的、、、2、、、、,这里用一个组合就可以了,要注意的是求组合的时候必须一边乘一边除掉,否则用__int64也会溢出,然后就是一个错排,错排的递推公式是dp[n]=(n-1)*(dp[n-1]+dp[n-2]);假设现在有5个位置,编号为1、2、3、4、5,有5个人编号为1、2、3、4、5,规定1号不能做1号位置,2号不能做2号位置、、、、,则dp[5]可以有dp[4]得出来,思想是假设现在有一个四个人的和四个位置的错排,现在添加一个5,第一种,先考虑当让这个5去做1号位置,然后分两种情况,第一种,1坐5的位置,这样就相当于3个人的错排,也就是dp[n-2],第二种,1不坐5的位置,这样就等于可以把1看成是5了,也就是4个人的错排,也就是dp[n-1],然后考虑的是先让5去坐2的位置,接下来就跟上面情况一样了,所以乘以一个(n-1),就得到了dp[n]=(n-1)*(dp[n-1]+dp[n-2]);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cmath> 3 __int64 dp[30]; 4 void dabiao() { 5 dp[0]=dp[1]=0,dp[2]=1; 6 for(__int64 i=3;i<=30;++i) 7 dp[i]=(dp[i-1]+dp[i-2])*(i-1); 8 dp[0]=1; 9 } 10 __int64 C(__int64 x,__int64 y) { 11 if(y==0) 12 return 1; 13 __int64 s=1; 14 for(__int64 i=x;i>=x-y+1;--i) { 15 s*=i; 16 s/=(x-i+1); 17 } 18 return s; 19 } 20 int main() { 21 dabiao(); 22 __int64 n; 23 while(scanf("%I64d",&n)&&n) { 24 __int64 sum=0,leiji=1,chu=1; 25 for(__int64 i=0;i<=n/2;i++) 26 sum+=dp[i]*C(n,i); 27 printf("%I64d\n",sum); 28 } 29 return 0; 30 }