刷題 子集和問題的回溯剪枝解法

2021-10-24 19:15:31 字數 2809 閱讀 6354

輸入給定整數集,問是否存在該整數集的子集,使得該子集元素的和為0

比如給定的整數集合為 [-7, -3 ,-2, 5, 8],存在集合的子集 [-3, -2, 5],該子集和為0。

input: 

-2 -3 4 5

0output:

1101

0000

這裡不給出**,如果有興趣可以去看一下 程老師 的書。

傳統解法的思路是:直接窮舉出所有子集合,保留其和為目標數的子集合。

這種做法無論空間複雜度還是時間複雜度都是 o(2

n)

o(2^n)

o(2n

),可謂效率低下,事倍功半。

這裡給出優化的解法,

遺憾的是,這種解法並不能降低演算法的時間複雜度

這只能在原本的複雜度下做出優化,減少在某些情況下的計算次數。

這種解法被稱作回溯剪枝

規定: x

ix_i

xi​為第 i

ii 層的棧資訊(0 or 1)

w

iw_i

wi​為第 i

ii 層的數字資訊(即輸入陣列第 i

ii 個元素的大小)

t

tt 是目標數

向右遍歷0 不選

向左遍歷 1 選

初始化 棧(用來儲存軌跡)、中間結果。

遞迴遍歷狀態樹 規定:目前的深度為 kkk

如果中間結果與目標結果一致,儲存棧資訊

若 ∑ i=

1kwi

×xi+

wk

>

t\sum^_w_i \times x_i + w_k > t

∑i=1k​

wi​×

xi​+

wk​>

t 對左子樹剪枝

若 ∑ i=

1kwi

×xi+

∑j=k

+1nw

j−wk

<

t\sum^_w_i \times x_i +\sum^_w_j - w_k < t

∑i=1k​

wi​×

xi​+

∑j=k

+1n​

wj​−

wk​<

t 對右子樹剪枝

由於是棧信息儲存結果,輸出之前要對棧做乙個pour的操作(反轉棧),使其輸出與預期匹配。

篇幅有限,就不將完整的遍歷過程給出,請讀者自行模擬。

os:macos catlina 10.15.6

cpu架構: x86_64

library

#include #include #include
核心實現

using

namespace

::std;

void

back_tracking

(int t,vector<

int> set,

int n,

int mid_rs,

int rest,

int target, stack<

int> decision,vectorint>>

&result)

}// 剪枝

else

// 搜尋右子樹 0

if( mid_rs+ rest -set[t]

>= target )

}// 回溯

}

測試**:

int

main()

;//為了正向顯示 pour操作

stack<

int> r;

int n=

int(set.

size()

);int rest=0;

int target =0;

for(

auto it=set.

begin()

;it!=set.

end(

);it++

)return0;

}

結果: ( **已除去多餘用作測試的 printf() **)

1 1 0 1 

0 0 0 0

本來程老師布置作業時要求的是寫本文 傳統解法 的,但是最近做了 0-1揹包問題對回溯演算法感到興趣,又看到程老師的 [b站課程]

(便想辦法優化書上的解法。

回溯演算法在這裡僅僅只是在可以剪枝的狀況下減少一部分運算規模,並不能做到降低複雜度級別的優化

遞迴的實現方式雖然可以降低堆中建棧這樣的開銷,但是仍然會在大量資料規模下,產生棧溢位的異常。

遞迴的方式在實際生產中不夠安全,容易產生棧溢位漏洞。

《design and analysis of algorithm using python》 程振波等著 清華大學出版社

學習筆記 | 演算法設計 | 回溯法剪枝函式解決子集和問題(c語言和matlab)

子集和問題 回溯

子集和問題的乙個例項為 s,t 其中,s 是乙個正整數的集合,c是乙個正整數。子集和問題判定是否存在s的乙個子集s1,使得 sum s1 c。試設計乙個解子集和問題的回溯法。對於給定的正整數的集合s 和正整數c,計算s 的乙個子集s1,使得 sum s1 c。輸入資料的第1 行有2 個正整數n 和c...

回溯法 子集和問題

問題 給定n個正整數wi和乙個正整數m,在這n個正整數中找出乙個子集,使得子集中的正整數之和等於m。解的形式 設定乙個n元組 x0,x1,xn 1 如果wi包含在這個子集中,xi就等於1,反之等於0.boundfunction 演算法偽 package com.iteye.caoruntao.sum...

子集和問題(回溯法)

第五章5 1 子集和問題 實驗報告 一 問題分析 處理的物件 給定的集合元素的個數和集合以及要湊成的和 要實現的功能 對於給定的集合,計算出它的乙個子集,使得子集內元素的和等於給出的正整數。這乙個子集就是最先計算出的那個子集 演算法思想 當我們給出集合個數n和要湊成的和m以及n個集合元素,我們使用乙...