字典序的下一个排列

时间:2023-02-02 20:27:06

先上模板

//数组a的下一个字典序排列。stl貌似会超时。手写还是快
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1025];

void next(int N)
{
int index = 0;
bool flag = false;
for(int i = N - 2 ; i >= 0 ; i--){
if(a[i] < a[i + 1]){//找第一个小于后一个数的数字
flag = true;
index = i;
break;
}
}
if(flag == flase){//这个序列已经是递减的排列,下一个肯定是递增的
sort(a ,a + N);
return;
}
int temp = index + 1;
//如果后面已经是递减了,那么就找到位于现在制定的两个数中间那个数换上来,并将后面按小到大排序
//例如1 2 4 3,假设现在index指向2,则temp指向4,i指向了3,因为3<4&&3>2所以将3与2交换,后面的按小到大排序
//因为这么做的前提是2后面是递减的,所以我们只要从最后找到一个最先位于index和tem之间的值即可,如此循环
for(int i = N - 1 ; i >= index + 2 ; i--){
if(a[i] < a[temp] && a[i] > a[index]){
temp = i;
break;
}
}
int change = a[index];
a[index] = a[temp];
a[temp] = change;
sort(a + index + 1 , a + N);
}

今天做了个poj1011,这是个组合数学的一个算法。今天学了一发,受教了。还查了一发证明,不仅感叹。。。牛逼。最近学离散的集合论,始终不知道是干啥的。。。好尴尬,虽然说,模板和证明都不是我自己的,但是!!!合起来就是我的。原创!
那个条件很烦直接上例子

例子更能说明:

假设输入为 5 5 2 4 7 6 3

从后往前观察,对于A[5] = 6 >= A[6] = 3。(交换A[5]和A[6]得到的排列: 5 5 2 4 7 3 6 小于原排列,这一步是没有必要做的,只是为了让大家看清楚)

A[4] = 7 >= A[5] >= A[6]。(交换A[4]和A[5]或者A[4]和A[6]等,得到的都比原排列小)

A[3] = 4 < A[4] >= A[5] >= A[6],这时从7 6 3中选择6,6是这三个数中大于4的最小的数,交换A[3] = 4和A[5] = 6,得到: 5 5 2 6 7 4 3

明显5 5 2 6 7 4 3比原排列大,但不是原排列的next permutation。

需要调整7 4 3得到最小的3 4 7,最终就是输出5 5 2 4 3 6 7
!!!!!!!!!!!!!!!!!!!!证明!!!!!!!!!!!!!!
这里写链接内容
证明写的极其帮!