【回溯法】求子集问题
给定一个集合比如{1,2,3},求该集合的所有子集。
对于集合中的每一个元素,在某一子集中只有两种状态,要么在子集中,要么不在子集中。
因此对于一个含有n个元素的集合来说,对其中的某一个元素i,用xi来表示其在某一子集中的状态,xi=1表示在子集中,xi=0表示不在子集中,因此,解可以表示为:
{x1,x2,x3,x4……xn};一共有2^n个向量。那么可以写代码如下.
程序代码:
#include<stdio.h>
#define MAX 100
void back(int i,int n);
int a[MAX];//存储集合元素
int count=0;//记录子集个数,其实没必要记录,因为count=2^n这是很显然的。
int b[MAX]={0};//存储集合元素状态
int k=1;//表示第k个元素,从1开始数
int main()
{
int i=0, n;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
back(1,n);//从第一个元素开始,确定第一个元素的状态
printf("%d",count);
return 0;
}
void back(int i,int n)
{
int j;
int sum =0;
if(i>n)//i>n表示所有元素的状态都已经确定,那么接下来打印出来
{
printf("{");
for(j=1;j<=n;j++)
{
if(b[j])
printf("%d,",a[j]);
//sum +=a[j];求子集之和
}
//printf("%d",sum);
printf("}\n");
count++;
return ;
}
{
b[i]=1;//取第i个元素
back(i+1,n);//处理下一个元素
b[i]=0;//不取第i个元素
back(i+1,n);//处理下一个元素
}
return ;
}
运行结果:
更进一步,求符合某条件的子集,比如子集和为m。
修改代码如下:
#include<stdio.h>
#define MAX 100
void back(int i,int n,int m);
int sum = 0;
int a[MAX];//存储集合元素
int count=0;//记录子集个数,其实没必要记录,因为count=2^n这是很显然的。
int b[MAX]={0};//存储集合元素状态
int k=1;//表示第k个元素,从1开始数
int main()
{
int i=0, n;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
back(1,n,10);//从第一个元素开始,确定第一个元素的状态
return 0;
}
void back(int i,int n,int m)
{
int j;
//int sum =0;
if(i>n)//i>n表示所有元素的状态都已经确定,但是其和不为m
{
return ;
}
b[i]=1;//取第i个元素
sum +=a[i];
if(sum == m)
{
printf("{");
for(j=1;j<=i;j++)
{
if(b[j])
printf("%d,",a[j]);
}
printf("}\n");
}
else if(sum<m)
{
back(i+1,n,10);//处理下一个元素
}
b[i]=0;
sum-=a[i];
back(i+1,n,10);//处理下一个元素
return ;
}
程序运行结果: