输入一个数n,下面输入n个数,求n个数的全排列;
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Max 50
int book[Max],tt[Max];
int a[Max],n;
void dfs(long long x )
{
if(x>n)
{
for(int i=1;i<=n;i++)
{
if(i==n) printf("%d\n",tt[i]);
else printf("%d ",tt[i]);
}
return ;
}
for(int i = 1; i<=n; i++)
{
if(!book[i])
{
book[i] = 1;
tt[x] = a[i];
dfs(x+1);
book[i] = 0;
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
memset(book,0,sizeof(book));
dfs(1);
}
return 0;
}
也可以直接用c++的函数库中的全排列函数 next_permutaton(a,a+n,cmp);
cmp,可加可不加,不加就是全排列,加上,就是自己定义一个cmp函数,按照自己定义的函数里的return条件,所排列;
下面一个n,输入n个数,求n的数的子集
思路:可以用全排列求:但像1,2,3 和 3,2,1 和2,1,3 ...,这些只要其中的一组就行了
所以可以在存到数组中时,加上一个条件,代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Max 50
int book[Max],tt[Max];
int a[Max],n;
void dfs(long long x )
{
for(int i = 1; i<=n; i++)
{
if(!book[i]&&tt[x-1]<=a[i])
{
book[i] = 1;
tt[x] = a[i];
for(int j = 1;j <=x;j++)
{
if(j==x) printf("%d\n",tt[j]);
else printf("%d ",tt[j]);
}
dfs(x+1);
book[i] = 0;
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
memset(book,0,sizeof(book));
dfs(1);
}
return 0;
}
加上一个条件 a[x-1]<=a[i] ,这个条件使得tt[] 数组中存的数是递增的;这样就避免重复子集的发生;
也可以这样 定义 一个 top 在 top 之前的数,都不在进入栈中这样可以避免重复
和上一个条件的区别就是 上一个输出的数单调递增的,而这个是取决于输入n的数的顺序,在top之前的数是不可以在进栈,不可在进入tt[] 数组中
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Max 50
int book[Max],tt[Max];
int a[Max],n;
void dfs(int top,int x )
{
for(int i = top; i<=n; i++)
{
if(!book[i])
{
book[i] = 1;
tt[x] = a[i];
for(int j = 1;j <=x;j++)
{
if(j==x) printf("%d\n",tt[j]);
else printf("%d ",tt[j]);
}
dfs(i+1,x+1);
book[i] = 0;
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
memset(book,0,sizeof(book));
dfs(1,1);
}
return 0;
}
以后避免像1,2,3 或3,2,1或2,1,3等这6种排列,只需要其中的一种就行了,以后就这样,简化上一个代码,仔细想想,top 之前的都不会再入栈了,那么book数组加不加是不是不起作用了,避免重复最简代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Max 50
int book[Max],tt[Max],num;
int a[Max],n;
void dfs(int top,int x) // 为了避免重复,定义了一个top,在top之前的都不在入栈;
{ // 那每个数还用不用标记了,答案是不用了,根本遍历不到在它之前的数,所以根本就不用book[]数组标记了
for(int i = top; i<=n; i++)
{
tt[x] = a[i];
for(int j = 1;j <=x;j++)
{
if(j==x) printf("%d\n",tt[j]);
else printf("%d ",tt[j]);
}
dfs(i+1,x+1);
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
memset(book,0,sizeof(book));
dfs(1,1);
}
return 0;
}
可以仔细想想, 求子集用不用在每一栈中都遍历n个数,假设这n个数都满足条件,这不是每一栈都要递归n次后,才能结束吗,这时间复杂度太大了, 其实 求子集无非就是这个数选于不选的问题,定义一个光标top,当移动到这数时,这个数就两种情况 选或者不选,每个数的两种情况懂遍历完,不就可以了吗;
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Max 50
int book[Max];
int a[Max],n;
void dfs(int top) // 这个top可以比作为一个光标,这一行前后移动,
{ // 移动到这个数,这个数就有两种情况 选或者不选;
if(top>n)
{
int f =0;
for(int j = 1;j <=n;j++)
{
if(book[j])
{
if(!f)
{
printf("%d",a[j]);
f = 1;
}
else printf(" %d",a[j]);
}
}
if(f) printf("\n");
return ;
}
book[top] = 1; //这个数标记一下,选了
dfs(top+1);
book[top] = 0; //这个数变为不选;
dfs(top+1);
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
memset(book,0,sizeof(book));
dfs(1);
}
return 0;
}