• 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
    ", dp[n][n-k]);
    37 }
    View Code
  • 相关阅读:
    搜索入门练习题3 全组合 题解
    搜索入门练习题1 素数环 题解
    搜索入门练习题2 全排列 题解
    二分 大纲
    凸包
    快速幂&矩阵快速幂
    最长不下降子序列的优化
    poj 3190 Stall Reservations
    poj 2431 Expedition

  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8526327.html
Copyright © 2020-2023  润新知