UVa11077

11077 Find the Permutations
Sorting is one of the most used operations in real life, where Computer Science comes into act. It is
well-known that the lower bound of swap based sorting is nlog(n). It means that the best possible
sorting algorithm will take at least O(nlog(n)) swaps to sort a set of n integers. However, to sort a
particular array of n integers, you can always find a swapping sequence of at most (n ? 1) swaps, once
you know the position of each element in the sorted sequence.
For example consider four elements <1 2 3 4>. There are 24 possible permutations and for all
elements you know the position in sorted sequence.
If the permutation is <2 1 4 3>, it will take minimum 2 swaps to make it sorted. If the sequence
is <2 3 4 1>, at least 3 swaps are required. The sequence <4 2 3 1> requires only 1 and the sequence
<1 2 3 4> requires none. In this way, we can find the permutations of N distinct integers which will
take at least K swaps to be sorted.
Input
Each input consists of two positive integers N (1 N 21) and K (0 K < N) in a single line. Input
is terminated by two zeros. There can be at most 250 test cases.
Output
For each of the input, print in a line the number of permutations which will take at least K swaps.
Sample Input
3 1
3 0
3 2
0 0
Sample Output
312

题意:

       给出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)。

 1 #include <cstdio>
 2 #include <cstring>
 3 #define ULL unsigned long long
 4 const int maxn = 30;
 5 ULL f[maxn + 1][maxn + 1];
 6 int main(){
 7     memset(f,0,sizeof f);
 8     f[1][0] = 1;
 9     for(int i = 2 ; i <= 21 ; i++)
10         for(int j = 0 ; j < i ; j++){
11             f[i][j] = f[i - 1][j];
12             if(j) f[i][j] += f[i - 1][j - 1] * (i - 1);
13         }
14     int n,k;
15     while(scanf("%d%d",&n,&k) == 2 && n)
16         printf("%llu\n",f[n][k]);
17     return 0;
18 }
View Code

 

转载于:https://www.cnblogs.com/cyb123456/p/5820222.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值