集合最大子集演算法 折衷演算法

2021-10-12 08:22:54 字數 1923 閱讀 2489

我們直接來看乙個問題。

給定乙個由n個整數組成的集合,其中n <= 40,每乙個整數都小於或等於

我們用例子來說明。

【例題1】

輸入集合為 ,n=6, s = 42

也就是從集合的6個元素中選擇適當的元素組成乙個子集,使得子集所有元素的和最大,並且該和小於或等於42。

【答案】該子集為,它的元素和為34+5+2=41,就是滿足條件的最大子集和。

現在改變s的值,請你自己做下面的例子。

【例題2】

輸入集合為 ,n=6, s = 10

分析思路

最直接的演算法就是暴力搜尋:找到n個整數的所有可能的子集,檢查子集的元素和否小於或等於s,並從中找出元素和為最大的子集。

想法簡單暴力,我喜歡!

但是它是否可行呢?

我們來看看這種演算法的時間複雜度。

我們知道n個元素的集合,它的所有子集個數有

當n的值比較大,

折衷演算法

折衷演算法是一種搜尋技術。當輸入值比較小,但也不是小到可以採用暴力搜尋演算法時,往往可以採用折衷演算法。

折衷演算法的基本思路是將問題分成兩部分,分別單獨解決它們,然後合併,找出最後的解。將問題分成兩部分後,問題的規模比原來小,並使複雜度上得到簡化,因而有可能解決問題。

我們使用折衷演算法來解決上面的問題。下面是演算法的描述:

1)將原來的整數集合拆分為2個子集,例如a和b,a中包含前[n / 2]個整數,b中包括剩下的整數。

2)從集合a中找出所有可能的整數子集和,並且儲存在陣列x中。類似地,把集合b中所有可能的整數子集和,並儲存在陣列y中。這樣,陣列x和y的元素個數最多為

3)現在合併這兩個子問題:從陣列x和y中找出組合,使它們的和小於或等於s。

在第3)步中,一種合併方式是簡單地遍歷陣列y的所有元素,並關聯於陣列x的每個元素,以檢查每種關聯得到的和是否小於或等於s。這樣的時間複雜度為

怎麼辦呢?

為了使它不那麼複雜,可以先對陣列y進行排序,然後再依次迭代x的每個元素,對於x中的每個元素 x,使用二分搜尋法在y中找到最大元素 y,使得x + y <= s。

這裡的二分搜尋法有助於將複雜度從

也就是等於 

因此我們的最終執行時間複雜度為

看到沒有?與原有演算法相比,它大大降低了時間複雜度,使得用該演算法解決問題變得可行。

**實現

我們採用c++來實現該演算法,你可以嘗試執行下面的程式。

#include  

using namespace std; 

//定義型別的別名

typedef long long int llit; 

//定義陣列x和y,分別存放一半集合元素組成的可能的元素和

llit x[2000005],y[2000005]; 

//計算集合a中所有可能子集的元素之和,並且儲存在陣列x中

void calcsubarray(llit a, llit x, int n, int c) 

} //找到小於或等於s的最大可能元素和

llit solvesubsetsum(llit a, int n, llit s) 

} return max; 

} //主程式

int main() 

; int n=sizeof(a)/sizeof(a[0]); 

llit s = 10; 

printf("largest value smaller than or equal to given "

"sum is %lld\n", solvesubsetsum(a,n,s)); 

return 0; 

集合最大子集演算法 C4 5演算法2

設s是s個資料樣本的集合。假定類標號ci i 1,m 具有m個不同的值,設si是類ci中的樣本數。對乙個給定的樣本分類所需的期望資訊由下式給出 i是任意樣本屬於c i的概率,並用s i s來估計。設屬性a具有v個子集s i,s v 其中,s j包含s中這樣一些樣本,它們在a上具有值a j。如果a選作...

演算法 集合的子集

給定乙個集合,輸出它的所有子集。示例 給定集合 1,2,3 應該輸出 增量構造法,每次選擇乙個元素放到集合中,每次操作的結果即是乙個子集。遞迴操作,每次向當前集合中新增乙個比當前集合中最大的元素大1的數。from future import print function defprint subse...

最大子集和

選出乙個陣列裡的乙個連續子集,使這個子集相加的和為所有子集中最大。舉例 給定乙個陣列為 2,1,3,4,1,2,1,5,4 輸出結果為 4,1,2,1 他的元素相加和為6為所有子集中最大。函式原型 retcode maxsubarray int inputarr,int inputlen,int o...