UVA11077 Find the Permutations

题意

PDF
给出1~n的一个排列,可以通过一系列的交换变成{1,2,…,n}。比如{2,1,4,3}需要两次交换。给定n和k,统计有多少个排列至少需要k次交换才能变成{1,2,…,n}。

分析

将给出的排列P视为一个置换,并将其分解为循环,各循环间相互独立。

单元素循环是不需要交换的,两个元素的循环需要交换1次,3个元素的循环需要交换2次,…,c个元素的循环需要交换c-1次。

于是我们就可以采用递推的方式进行求解了。设f(i,j)表示至少需要交换j次才能变成{1,2,…,i}的排列个数。则f(i,j) = f(i - 1,j) + f(i – 1,j - 1) * (i - 1)。因为要么元素i自己形成一个循环,要么加入前面任意一个循环的任意一个位置。边界为f(1,0) = 1,f(1,j) = 0(j >= 1)。

时间复杂度(O(n^2))

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
    while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef unsigned long long ull;

co int N=22;
ull f[N][N];
int main(){
//	freopen(".in","r",stdin),freopen(".out","w",stdout);
	f[1][0]=1;
	for(int i=2;i<=21;++i)
		for(int j=0;j<i;++j){
			f[i][j]=f[i-1][j];
			if(j>0) f[i][j]+=f[i-1][j-1]*(i-1);
		}
	for(int n,k;read(n)|read(k);) printf("%llu
",f[n][k]);
	return 0;
}
原文地址:https://www.cnblogs.com/autoint/p/10641910.html