火星人(排列,贪心,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("\n");
    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("\n");
    return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号