題目
給定長度爲n(n<=9)的全排列,
輸出比該全排列上一個字典序的全排列,
不存在輸出ERROR
思路來源
https://www.luogu.com.cn/problemnew/solution/P2525
題解
組合數學惡補第二彈,orz這個可是洛谷入門題
考慮上一個字典序,一定出現在某一位比當前全排列小了,且是最靠後的一位
對於相鄰的正序對,無法交換其順序,所以一定是從後往前的第一個逆序對
若a[i-1]>a[i],則可以把a[i-1]調小,變成字典序更小的全排列,
所以找到範圍內滿足a[x]<a[i-1]且值最大的那個位置x,將其與a[i-1]交換,
交換之後,起到了降字典序的目的,後面的數應降序排列,使當前的字典序最大
代碼1
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=10;
int n,a[N],b[N],cnt;
bool ok;
void solve(int x){//[x,n)
int mx=-1,pos=-1;
for(int i=x+1;i<n;++i){//<a[x]的最大的 從最小的逆序一位開始調小
if(a[i]<a[x]){
if(a[i]>mx){
mx=a[i];
pos=i;
}
}
}
swap(a[pos],a[x]);
sort(a+x+1,a+n,greater<int>());//後面的降序即可 表示此時的最大
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d",&a[i]);
}
for(int i=n-1;i;--i){
if(a[i-1]>a[i]){
solve(i-1);
for(int j=0;j<n;++j){
printf("%d%c",a[j]," \n"[j==n-1]);
}
ok=1;
break;
}
}
if(!ok)puts("ERROR");
return 0;
}
代碼2(prev_permutation)
用STL水,調用該函數,若上一個全排列存在,則會使ai變成上一個全排列,否則返回假
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=10;
int n,a[N],b[N],cnt;
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d",&a[i]);
}
if(!prev_permutation(a,a+n))puts("ERROR");
else{
for(int i=0;i<n;++i){
printf("%d%c",a[i]," \n"[i==n-1]);
}
}
return 0;
}