zoukankan      html  css  js  c++  java
  • 嵊州D2T2 八月惊魂 全排列 next_permutation()

    嵊州D2T2

    八月惊魂

    这是一个远古时期的秘密,至今已无人关心。

    这个世界的每个时代可以和一个 1 ∼ n 的排列一一对应。

    时代越早,所对应的排列字典序就越小。

    我们知道,公爵已经是 m 个时代前的人物了。

    并且通过翻阅古籍,我们得知了公爵所在时代所对应的排列。

    那么我们的时代所对应的排列是什么?

    希望以此能寻回我们失落的文明……

    Input

    第一行一个正整数 n。

    第二行一个正整数 m。

    第三行 n 个整数,表示公爵所在时代对应的排列。

    Output 一行 n 个整数,表示我们所在的时代对应的排列。

    Examples

    august.in august.out

    5

    3

    1 2 3 4 5

    1 2 4 5 3

    Notes

    对于所有数据,满足 n ≤ 10000 , m ≤ 100。

    Task1[30%]

    n ≤ 10

    Task2[60%]

    n ≤ 50

    Task3[100%]

    无特殊限制


    Solve!

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int main(){
        //freopen("august.in","r",stdin);
        //freopen("august.out","w",stdout);
        int n,m; scanf("%d%d",&n,&m);
        int line[n];
        for(int i=0;i<n;i++) scanf("%d",&line[i]);
        while(m--) next_permutation(line , line + n);
        for(int i=0;i<n;i++) {printf("%d ",line[i]);}
        return 0;    
    }

     这篇博客园,之所以我要先code,是因为我连题目都看不懂

    时代越早,所对应的排列字典序就越小。

     是吗?字典序是什么呀~

    还要一个一个推吗?怎么推?

    于是我就搁着了。。。

    后来

    再看std(题解)

    next_permutation(line , line + n);

    这是什么函数呀?

    原来是STL里面的呀。。。

    真的没看过呀!!!o(╥﹏╥)o......

    next_permutation全排列函数是一个十分好用而且强大的函数。

    要想更好的了解这个函数可以看https://blog.csdn.net/howardemily/article/details/68064377

    排列(Arrangement),简单讲是从N个不同元素中取出M个,按照一定顺序排成一列,通常用A(M,N)表示。

    当M=N时,称为全排列(Permutation)

    从数学角度讲,全排列的个数A(N,N)=(N)*(N-1)*...*2*1=N!,但从编程角度,如何获取所有排列?那么就必须按照某种顺序逐个获得下一个排列,通常按照升序顺序(字典序)获得下一个排列。

    例如对于一个集合A={1,2,3,},首先获取全排列a1: 1,2,3,;然后获取下一个排列a2: 1,3,2,;

    按此顺序,A的全排列如下:

    a1: 1,2,3;  a2: 1,3,2;  a3: 2,1,3;  a4: 2,3,1;  a5: 3,1,2;  a6: 3,2,1;  共6种。

    对于给定的任意一种全排列,如果能求出下一个全排列的情况,那么求得所有全排列情况就容易了。

    好在STL中的algorithm已经给出了一种健壮、高效的方法,下面进行介绍。

    next_permutation()

    a)从后向前查找第一个相邻元素对(i,j),并且满足A[i] < A[j]。

    易知,此时从j到end必然是降序。可以用反证法证明,请自行证明。

    b)在[j,end)中寻找一个最小的k使其满足A[i]<A[k]。

    由于[j,end)是降序的,所以必然存在一个k满足上面条件;并且可以从后向前查找第一个满足A[i]<A[k]关系的k,此时的k必是待找的k。

    c)将i与k交换。

    此时,i处变成比i大的最小元素,因为下一个全排列必须是与当前排列按照升序排序相邻的排列,故选择最小的元素替代i。

    易知,交换后的[j,end)仍然满足降序排序。因为在(k,end)中必然小于i,在[j,k)中必然大于k,并且大于i。

    d)逆置[j,end)

    由于此时[j,end)是降序的,故将其逆置。最终获得下一全排序。

    注意:如果在步骤a)找不到符合的相邻元素对,即此时i=begin,则说明当前[begin,end)为一个降序顺序,即无下一个全排列,STL的方法是将其逆置成升序。

    next_permutation()拓展

    如何获取所有全排列情况?

    STL中的代码非常精妙,利用next_permutation的返回值,判断是否全排列结束(否则将死循环)。对于给定的一个数组,打印其所有全排列只需如下:

    1 void all_permutation(int arr[], int n)
    2 {
    3     sort(arr,arr+n);    // 先用sort排序
    4     do{//用do……while保证至少做一遍
    5         for(int i=0; i<n; printf("%d ",arr[i++]));
    6         printf("
    ");
    7     }while(next_permutation(arr,arr+n));//判断也是计算
    8 }
    All Permutation

    请循其本

    所以,我们的代码呢,只要一行(核心部分)呢!

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 int main(){
     5     //freopen("august.in","r",stdin);
     6     //freopen("august.out","w",stdout);
     7     int n,m; scanf("%d%d",&n,&m);
     8     int line[n];
     9     for(int i=0;i<n;i++) scanf("%d",&line[i]);
    10     while(m--) next_permutation(line , line + n);
    11     for(int i=0;i<n;i++) {printf("%d ",line[i]);}
    12     return 0;    
    13 }

    别忘记加头文件哈!

    #include <algorithm>

    OK!

  • 相关阅读:
    南阳1071
    hdu5110 dp
    hdu1199 线段树
    hdu5107 线段树
    hdu5106 数位dp
    hdu 5103 状态压缩dp
    C Strange Sorting
    hdu5102 枚举每条边的长度
    uva672
    uva473
  • 原文地址:https://www.cnblogs.com/send-off-a-friend/p/11178134.html
Copyright © 2011-2022 走看看