1. 程式人生 > 其它 >求子集的兩種方法(模擬法,dfs法)

求子集的兩種方法(模擬法,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);

}