P1088 [NOIP2004 普及组] 火星人

// Problem: P1088 [NOIP2004 普及组] 火星人
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1088
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// User: Pannnn
#include <bits/stdc++.h>
using namespace std;
/*
下一个排列总是比当前排列要大,除非该排列已经是最大的排列。
希望找到一种方法,能够找到一个大于当前序列的新序列,且变大的幅度尽可能小。
需要将左边的一个较小数与右边的一个较大数交换,以能够让当前排列变大,从而得到下一个排列。
同时要让这个较小数尽量靠右,而较大数尽可能小,当交换完成后,
较大数右边的数按照升序重新排列,可以保证新排列大于原来排列的情况下,使变大的幅度尽可能小。
以4 5 2 6 3 1为例
能找到的符合条件的一对较少数与较大数的组合为2 3,满足较小数尽可能靠右且较大数尽可能小
完成交换后,排列变为4 5 3 6 2 1,此时重排原来较小数位置右边的序列,序列变为4 5 3 1 2 6
描述算法:
对于长度为n的排列a:
首先从后向前查找第一个顺序对(i, i + 1),满足a[i] < a[i + 1],这样较小数为a[i],此时[i + 1, n)必然为降序
如果找到了顺序对,那么在区间[i + 1, n)中从后向前查找第一个元素j满足a[i] < a[j],这样较大数为a[j]
交换a[i]与a[j],此时可以证明区间[i + 1, n)必为降序,可以直接反转使其变为升序
*/
void nextPermutation(vector<int> &nums) {
int i = nums.size() - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
--i;
}
if (i >= 0) {
int j = nums.size() - 1;
while (j >= 0 && nums[i] >= nums[j]) {
--j;
}
swap(nums[i], nums[j]);
}
reverse(nums.begin() + i + 1, nums.end());
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
cin >> n >> m;
vector<int> info(n);
for (int i = 0; i < n; ++i) {
cin >> info[i];
}
for (int i = 0; i < m; ++i) {
nextPermutation(info);
}
for (int i = 0; i < n; ++i) {
cout << info[i] << " ";
}
cout << endl;
return 0;
}
posted @   Pannnn  阅读(152)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
-->
点击右上角即可分享
微信分享提示