UVA11077 Find the Permutations —— 置换、第一类斯特林数

题目链接:https://vjudge.net/problem/UVA-11077

 

题意:

问n的全排列中多有少个至少需要交换k次才能变成{1,2,3……n}。

 

题解:

1.根据过程的互逆性,可直接求{1,2,3……n}至少需要交换多少次才能变成{a1,a2,a3……an},因此可直接把{a1,a2,a3……an}看成是{1,2,3……n}的置换。为什么呢?

答:1 2 3

  2 3 1  可知把“2 3 1”看作是经过置换后的序列,则:2-->1(2放到1)、3-->2(3放到2)、1-->3(1放到3)。

         把“2 3 1”看作是置换,                        则:1-->2(1放到2)、2-->3(2放到3)、3-->1(3放到1)。

所以把序列看成是置换的话,那么它与变成自己的置换的形状完全相同,只是所有箭头的方向都发生了改变。

2.将一个置换分解成若干个循环,对于一个长度为len的循环,需要交换len-1次才能使得里面的每一个元素回到自己的位置(每一次交换都能使得一个元素回到原来的位置,一直交换到最后一个,就直接在自己的位置上。所以位len-1)。

3.根据第二点,即有多少个循环,就能减少多少次交换。而交换了k次,即减少了n-k交换,因此也就有n-k个循环。把n个有区别的元素排列成n-k个循环(圈),即为第一类斯特林数。

 

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 30;
18 
19 unsigned long long dp[MAXN][MAXN];
20 void init()
21 {
22     memset(dp, 0, sizeof(dp));
23     for(int i = 1; i<=21; i++)  //第一类斯特林数
24     {
25         dp[i][0] = 0; dp[i][i] = 1;
26         for(int j = 1; j<i; j++)
27             dp[i][j] = 1LL*dp[i-1][j-1] + 1LL*(i-1)*dp[i-1][j];
28     }
29 }
30 
31 int main()
32 {
33     init();
34     int n, k;
35     while(scanf("%d%d", &n, &k)&&(n||k))
36         printf("%llu\n", dp[n][n-k]);
37 }
View Code

 

转载于:https://www.cnblogs.com/DOLFAMINGO/p/8526327.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值