求子集的两种方法(模拟法,dfs法)

方法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);

}

posted @ 2021-08-08 11:32  pcpcppc  阅读(877)  评论(0编辑  收藏  举报