火星人(排列,贪心,next_permutation)

题意

给定一个(n)个数的排列,求比这个排列大的第(m)个排列。
规定始终有解

数据范围

(1 leq n leq 10000)
(1 leq m leq 100)

思路

  • 首先这题可以直接用next_permutation(a, a + n)秒杀。跑(m)次后的排列,即为最终答案
  • 考虑next_permutation是怎么实现的。从后向前扫描序列,找到第一个(a[i] > a[i - 1])的位置,因为只有当序列单调下降时,它才不存在更大的排列。
    然后将(a[i - 1])与后面比它大的最小数交换。
    然后将(a[i - 1])后面的数从小到大排序,这里因为是单调递减的,因此逆序一下就行了。
    得到的排列就是比原排列大的最小排列了。

代码

  • next_permutation版本
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 10010;

int n, m;
int a[N];

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i ++) scanf("%d", &a[i]);
    while(m --) next_permutation(a, a + n);
    for(int i = 0; i < n; i ++) printf("%d ", a[i]);
    printf("
");
    return 0;
}
  • 手写版
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 10010;

int n, m;
int a[N];

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i ++) scanf("%d", &a[i]);
    while(m --) {
        int k = 0;
        for(int i = n - 1; i > 0; i --) {
            if(a[i] > a[i - 1]) {
                k = i - 1;
                break;
            }
        }
        int t = n - 1;
        for(int i = k + 1; i < n; i ++) {
            if(a[i] < a[k]) {
                t = i - 1;
                break;
            }
        }
        swap(a[k], a[t]);
        reverse(a + k + 1, a + n);
    }
    for(int i = 0; i < n; i ++) printf("%d ", a[i]);
    printf("
");
    return 0;
}
原文地址:https://www.cnblogs.com/miraclepbc/p/14340082.html