http://ccutchi.openjudge.cn/practice/1099/
描述已知1到n的序列:1,2,3...n-1,n。求该序列的全部升序组合。
1
2
3
1 2
1 3
2 3
1 2 3
每个测试样例后面有一个空行
2 3 0
1 2 1 2 1 2 3 1 2 1 3 2 3 1 2 3
第一种暴力深搜再排序:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define N 17
int n;
bool flag[N];
char str[34000][17];
int c;
int cmp(const void *a,const void *b)
{
char *aa=(char *)a;
char *bb=(char *)b;
if(strlen(aa)==strlen(bb))
return strcmp(aa,bb);
return strlen(aa)-strlen(bb);
}
void display()
{
bool f=1;
int p=0;
for(int j=1;j<=n;j++){
if(flag[j]){
f=0;
str[c][p++]=j;
}
}
if(!f){
str[c][p]='\0';
c++;
}
}
void dfs(int x)
{
for(int i=x;i<=n;i++){
flag[i]=1;
display();
dfs(i+1);
flag[i]=0;
}
}
int main()
{
// freopen("zh.in","r",stdin);
// freopen("zh.out","w",stdout);
while(scanf("%d",&n),n){
memset(flag,0,sizeof(flag));
c=0;
dfs(1);
qsort(str,c,sizeof(str[0]),cmp);
for(int i=0;i<c;i++){
printf("%d",(int)str[i][0]);
for(int j=1;j<strlen(str[i]);j++){
printf(" %d",(int)str[i][j]);
}
puts("");
}
puts("");
}
return 0;
}
第二种巧妙的位运算特性来模拟:
#include <cstdio>
#include <cstring>
#include <cstdlib>
char subs[34000][17];
//3位的二进制有001,010,011,100,101,110,111的组合是一个全组合,因此可按此原理模拟
int cmp(const void *a,const void *b)
{
char *aa=(char *)a;
char *bb=(char *)b;
if(strlen(aa)==strlen(bb))
return strcmp(aa,bb);
return strlen(aa)-strlen(bb);
}
int main()
{
int n;
while(scanf("%d",&n),n){
int c=0;
int h=1<<n;
for(int i=1;i<h;i++){
int p=0;
for(int j=0;j<n;j++){
int temp=i;
if(temp & (1<<j)){
subs[c][p++]=j+1;
}
}
if(p!=0){
subs[c][p]='\0';
c++;
}
}
qsort(subs,c,sizeof(subs[0]),cmp);
for(int i=0;i<c;i++){
printf("%d",(int)subs[i][0]);
for(int j=1;j<strlen(subs[i]);j++){
printf(" %d",(int)subs[i][j]);
}
puts("");
}
puts("");
}
return 0;
}
这种方法的运算速度要快得多,前提得了解位运算。