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