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

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM