UVA11077 循环群计数
1 /*UVA11077 2 循环群计数 3 n个数的排列数P(n)=n! 4 一个n的排列可以通过两两交换变成一个(123..n)的顺序排列 5 判断方法我们熟知,把这个排列写生不相交循环,最少操作数d=n-循环群个数x 6 现在问题求的是多少个n的排列至少通过k次两两交换。 7 现在逐步分析: 8 设f(n,k)为n的排列,通过k次最少交换 9 f(n,k)=f(n-1,k)+f(n-1,k-1)*(n-1)//这点白书上有错误 10 解释:f(n-1,k-1),循环群个数n-k个,变成f(n,k),不需要新增循环群,将数字n插入前n-1个位置都可 11 同理,f(n-1,k),循环群个数n-k-1个,变成f(n,k),要新增一个循环群,故n单独成循环群,放置在最后 12 边界f(i,0)=1;其他为0 13 注意测试大数字 14 */ 15 #include<iostream> 16 #include<stdio.h> 17 #include<string.h> 18 #include<algorithm> 19 #include<stdlib.h> 20 #include<math.h> 21 #include<queue> 22 #include<vector> 23 #include<map> 24 #define ULL unsigned long long 25 using namespace std; 26 27 int n,k; 28 ULL F[25][25]; 29 void init(){ 30 memset(F,0,sizeof(F)); 31 for(int i=1;i<=21;i++)F[i][0]=1; 32 for(int i=2;i<=21;i++){ 33 for(int j=1;j<i;j++) 34 F[i][j]=F[i-1][j-1]*(i-1)+F[i-1][j]; 35 } 36 return ; 37 } 38 int main(){ 39 init(); 40 while(cin>>n>>k ){ 41 if (n==0 && k==0) break; 42 cout<<F[n][k]<<endl; 43 44 } 45 return 0; 46 }