方法1:模拟法
我们以(1,2,3)这个集合为例手动模拟一遍
该集合的子集分别为:
一:空集
二:1
三:12
四:123
五:13
六:2
七:23
八:3
我们分析一下这个过程,选择第一个数字,选择其之后的数字依次加入,到了边界后退回,直到遍历完第一个数字的所有子集,然后对第二个数字重复同样的操作,直到把集合内所有的数字遍历完
不难发现,这个过程是一直向后的,被遍历完所有子集的数字不会再次出现,这也保证了不会重复计算,接下来我们就可以开始实现了
我们设一个数组a[]用来存放原集合,一个数组b[]用来存放子集,变量now表示现在正在原集合的第几个数字上,变量num表示现在正在子集的第几位上
void solve (int now,int num)
{
if(now>n)return; //边界条件
for(int i=now;i<=n;i++) //从原集合中依次选择元素加入子集,从now开始意味着只能选择当前元素及以后的元素加入
{
b[num]=a[i]; //选择当前位置的子集的元素
for(int j=1;j<=num;j++)
cout<<b[j]<<" ";
cout<<endl; //打印
solve(i+1,num+1); //num+1意味着开始选择子集的下一位元素,i+1意味着接下来将会从当前元素之后的元素里选择
}
}
方法2:dfs法
不难发现,对于原集合中的每一个元素,都只存在两种情况:子集中有它,子集中没有它,等价一下就变成了:选择把它加入子集,选择不把它加入子集,接下来就可以开始实现了
我们设一个bool数组vis[]用来判断每个元素是否被选择,vis[]=1代表被选择,now 的定义同上
void dfs(int now)
{
if(now>n)
{
for(int i=1;i<=n;i++)
if(vis[i]) //如果这个元素被选择了就打印
cout<<b[i];
cout<<endl;
return;
} //边界+打印
vis[i]=1;//表示选择这个元素
dfs(now+1);
vis[i]=0;//表示不选择这个元素
dfs(now+1);
}