标签:
赛诗会后,十二金钗待奔前程。分别宴上,12人各写了一首诗放入包囊。
大家随机取一个,若取到自己的诗,则再取一个,并放回自己的诗,12人都拿到诗算一种分配。
请问:共有多少种不同的分配?
问题简化:给定n个人写n首诗,要求赠给其他人,共有多少种分配方法。
通俗一点就是:1到n的全排列,第i个数不是i的排列共有多少种?
其实这就是“错位排序”。
(错位排序问题的答案可以由“错排公式”求得,关于错排公式的推导可以参考百度百科:http://baike.baidu.com/view/668994.htm)
这里简单从类似动态规划的角度来分析问题:
假设n个数的错位排序数目为dp[n]
第n个数可以放置在1...(n-1)之间的任何一个位置,共(n-1)种方法;
假设第n个数放在了第k个位置,那么对于数字k而言:
如果放在了第n个位置,那么相当于n和k做了交换,剩下的就是其他(n-2)个数的错位排序了,即dp[n-2];
如果不放在第n个位置,那么剩余(n-1)个数(可以将此时k看出原来的n,即此时剩下除了k位置外的所有数),即dp[n-1];
因此动态规划的状态转移方程为:
dp[n]=(n-1)*(dp[n-1]+dp[n-2]);
初始状态:
当n=1;dp[1]=0;
当n=2;dp[2]=1;(两个数,只存在一种错排的可能)
通过上述公式的递推可以得到“错排公式”:
D(n) = n! [1/0! - 1/1! + 1/2! - 1/3! + 1/4! + ... + (-1)^n/n!].
#include <iostream>
using namespace std;
int miscombination_1(int n){
int A[n+1];
A[1]=0;
A[2]=1;
for(int i=3;i<=n;i++)
A[i]=(i-1)*(A[i-1]+A[i-2]);
return A[n];
}
int miscombination_2(int n){
if(n<=2)
return n-1;
int first=0;
int second=1;
int third=0;
for(int i=3;i<=n;i++){
third=(i-1)*(first+second);
first=second;
second=third;
}
return third;
}
int main()
{
cout << miscombination_1(12) << endl;
cout << miscombination_2(12) << endl;
return 0;
}
问题答案:
176214841
标签:
原文地址:http://www.cnblogs.com/AndyJee/p/4636075.html