您的位置:首页 > 其它

hdu1027 next_permutation的应用

2017-09-15 20:49 330 查看
博文参考:http://www.cnblogs.com/luruiyuan/p/5914909.html讲的很棒

题目求n个数按字典序的第m个排列,有prev_permutation,next_permutation等现成函数。

在此介绍一下next_permutation的实现过程:
方便理解,首先对1,2,3,4,5这5个数进行分析:
1:将1,2,3固定,对4操作,易得1,2,3,5,4
2:将1,2,固定,对3操作,找到3后面大于3的最小数4,swap(3,4),得到1,2,4,5,3,此时5,3是个逆序,明显不满足,所以将5,3翻转,得到1,2,4,3,5
……
从上面的过程中可以发现当前序列的后面部分一定存在一个完全逆序的子序列,比如1,2,3,4,5的逆序子序列只有5,而1,2,3,5,4的逆序子序列则是5,4,很明显后面的逆序部分已经达到最大,想要下一步得到更大的排列,只能对前一位进行操作,对1,2,3,5,4而言,也就是3,这时我们选择的应该是后面部分大于3的最小数,也就是4,进行对调,易得,对调后后面部分依然是逆序,此时我们应该执行翻转操作,变成正序。
通过对上面的理解,prev_permutation也容易懂了(~

),我们应该寻找当前序列的后面正序部分,然后将前一位(设为x)与后面正序部分小于x的最大数,对调,然后翻转。bool next_permutation(int* start,int* end){
int *temp1=end-1,*temp2=temp1-1;
while(*temp1<=*temp2&&temp2<=start) temp2--,temp1--;//寻找正序
if(temp2<start) return false;
for(temp1=end-1;*temp1>=*temp2;temp1--);//寻找正序部分小于x的最大数
swap(temp1,temp2);
reverse(temp2+1,end);
return true;
}ac代码:#include<iostream>
#include<cstring>
using namespace std;
int s[1005];
void swap(int* s,int* e){
int t=*s;
*s=*e;
*e=t;
}
void reverse(int* s1,int* e1){
e1--;
while(s1<e1) swap(s1,e1),s1++,e1--;
}
bool next_permutation(int* start,int* end){
int *temp1=end-1,*temp2=temp1-1;
while(*temp1<=*temp2&&temp2>=start
4000
) temp2--,temp1--;
if(temp2<start) return false;
for(temp1=end-1;*temp1<=*temp2;temp1--);
swap(temp1,temp2);
reverse(temp2+1,end);
return true;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++) s[i-1]=i;
for(int i=1;i<m;i++) next_permutation(s,s+n);
for(int i=0;i<n-1;i++) printf("%d ",s[i]);
printf("%d\n",s[n-1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: