对于“下一个排列”,一开始不懂子集与搜索的概念,就穷举了好多种情况,发现了其中的规律
算法如下:
1. 对给定的排列,从右到左扫描各个字符,如果这些字符从右到左是按字典序递增的,该排列就是最后一个,没有下一个排列。
2. 从右到左扫描各个字符,如果第k个字符不是按字典序递增的,下一个排列可以将第k个字符增加一位后修改得到。
3.将第k个字符增加一位后,可能与该字符前缀中的字符重复,那就再增加一位,直到与前缀中的字符不重。
4.若第k个字符增加一位后,仅与该字符后缀中的字符重复,那就与后缀中重复的字符互换。
5.执行第4步后,保留前缀和新的第k个字符,将后缀的字符按字典序重新排列就得到原排列紧接的排列。
以下是代码实现:
char* next_permutation(char *str)
{
int t,m,temp;
int l=strlen(str);
for(int i=l-1; i>=0; i--)
{
if(str[i-1]<str[i])
{
t=i;
break;
}
}
if(t==0)
return NULL;
else
{
for(int i=l-1; i>=0; i--)
{
if(str[i]>str[t-1])
{
m=i;
break;
}
}
temp=str[t-1];
str[t-1]=str[m];
str[m]=temp;
for(int i=0; i<l-t; i++)
{
for(int j=l-1-i; j<l-1; j++)
{
if(str[j]>str[j+1])
{
temp=str[j];
str[j]=str[j+1];
str[j+1]=temp;
}
}
}
return str;
}
}
当然,也可以直接用STL库里的next_permutation函数,需要加头文件<algorithm>
附:题目
POJ 1731 - Orders(全排列)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
char a[10000];
while(cin>>a)
{
sort(a,a+strlen(a));
cout<<a<<endl;
while(next_permutation(a,a+strlen(a)))
{
cout<<a<<endl;
}
}
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
char* next_permutation(char *str)
{
int t,m,temp;
int l=strlen(str);
for(int i=l-1; i>=0; i--)
{
if(str[i-1]<str[i])
{
t=i;
break;
}
}
if(t==0)
return NULL;
else
{
for(int i=l-1; i>=0; i--)
{
if(str[i]>str[t-1])
{
m=i;
break;
}
}
temp=str[t-1];
str[t-1]=str[m];
str[m]=temp;
for(int i=0; i<l-t; i++)
{
for(int j=l-1-i; j<l-1; j++)
{
if(str[j]>str[j+1])
{
temp=str[j];
str[j]=str[j+1];
str[j+1]=temp;
}
}
}
cout<<str<<endl;
next_permutation(str);
}
}
int main()
{
char a[10000];
while(cin>>a)
{
sort(a,a+strlen(a));
cout<<a<<endl;
next_permutation(a);
}
return 0;
}
UVa 10098 - Generating Fast
同样是全排列,只需注意输出换行,代码就不给出了
UVa 146 - ID Codes(下一个排列)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
char a[10000];
while(gets(a)!=NULL)
{
if(strcmp(s,"#")==0)break;
next_permutation(a,a+strlen(a));
cout<<a<<endl;
}
return 0;
}
UVa 729 - The Hamming Distance Problem(二进制全排列)
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
char a[100];
int ncase,n,b;
cin>>ncase;
while(ncase--)
{
cin>>n>>b;
for(int i=0;i<n-b;i++)a[i]='0';
for(int i=n-b;i<n;i++)a[i]='1';
a[n]='\0';
while(next_permutation(a,a+strlen(a))
cout<<a<<endl;
if(ncase)cout<<endl;
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void next(char *str)
{
int i,j,l,t,m,temp;
l=strlen(str);
for(i=l-1; i>=0; i--)
{
if(str[i-1]<str[i])
{
t=i;
break;
}
}
if(t==0)
return;
else
{
for(i=l-1; i>=0; i--)
{
if(str[i]>str[t-1])
{
m=i;
break;
}
}
temp=str[t-1];
str[t-1]=str[m];
str[m]=temp;
for(i=0; i<l-t; i++)
{
for(j=l-1-i; j<l-1; j++)
{
if(str[j]>str[j+1])
{
temp=str[j];
str[j]=str[j+1];
str[j+1]=temp;
}
}
}
printf("%s\n",str);
next(str);
}
}
int main()
{
char a[100];
int e,i,j,l,t,Case,n;
scanf("%d",&Case);
for(e=0; e<Case; e++)
{
scanf("%d%d",&l,&n);
for(i=0; i<l; i++)
a[i]='0';
for(i=l-1,j=0; j<n; j++,i--)
a[i]='1';
a[l]='\0';
puts(a);
next(a);
if(e<Case-1)
putchar('\n');
}
return 0;
}