最近在開發某專案,遇到這樣乙個需求:在乙個賬單記錄的table中,記錄著每張賬單及其金額,要求使用者輸入乙個金額,從表中取出金額組合為該金額的賬單【可能有很多個解,但只需要提供一例】。
這題目看起來很簡單,只是把數加起來判斷,但仔細一想,難度不小。因為組合的個數沒有確定,可以直接找到,即1個,或者2個,3個……n個組成,那麼原先想要使用的for迴圈就無法使用了,因為不知道要巢狀多少層,而且跟後來的方法相比效率較低。
後來在網上查了好久,查到了這原來這叫做子集和問題,是什麼0-1揹包之類的問題【資料結構學得一般t^t】需要用遞迴或回溯解決。因為我只需要求出一解,所以我選擇了回溯法。遞迴將顯示所有組合,但我並不需要。下面是仿照別人的思路寫出的**,我將一一注釋。
1static
void main(string
args)
2;//
測試用的陣列
4bool flag = ;//
標誌陣列,與測試陣列對應,true代表該數在組合中,false則不在
5 bubble(test);//
冒泡,其實不排序也可以
6int target =convert.toint32(console.read());
7bool result =backtrace(test, flag, target);89
if (result == true)10
, ", test[i]);15}
16}17else
1821
console.writeline();22}
2324
static
bool backtrace(int a, bool flag, int
target)
2542 index++;//
繼續檢驗下一元素43}
4445
//如果索引到了最後,還沒有找到合適的組合,那麼將回溯.一般來說會出現*100011或*1000的情況,即此時flag中的元素應該在某個1之後有若干個0或01組合【先0後1】, [i個數] 1 [j個0][k個1]這樣的情況,回溯到1的位置,將其變為0,然後繼續往下迴圈檢驗.從後面回溯的時候,將1變為0,遇0不變.如果回溯到首位,則說明沒有合適的組合存在.
4647
if (index >=a.length)
4857
58while (flag[index - 1] == false)//
如果不在組合中,往前回溯
5964 flag[index - 1] = false
;65 sum -= a[index - 1
];66}67
68}69return
false;70
71}7273
static
void bubble(int
a)7484}
8586
foreach (int k in
a)87 console.write(", "
, k);
88console.writeline();
89 }
還應注意console.readline(),讀入的是字串,要經過convert.toint32()的處理,因為輸入的是字串,其值與字面值不一致.
此外應該還可以再優化,但過幾個鐘還要上班,還是睡覺去吧.
ps:我不是通宵工作,我從10點睡到4點半,睡不著就起床寫一下部落格。程式設計師要記得勞逸結合哦!
子集和問題(回溯法)
第五章5 1 子集和問題 實驗報告 一 問題分析 處理的物件 給定的集合元素的個數和集合以及要湊成的和 要實現的功能 對於給定的集合,計算出它的乙個子集,使得子集內元素的和等於給出的正整數。這乙個子集就是最先計算出的那個子集 演算法思想 當我們給出集合個數n和要湊成的和m以及n個集合元素,我們使用乙...
子集和問題(回溯法)
給定乙個含有n個元素的整形陣列a,再給定乙個和sum,求出陣列中滿足給定和的所有元素組合,舉個例子,設有陣列a 6 sum 10,則滿足和為10的所有組合是 注意,這是個n選m的問題,並不是兩兩組合問題 最直觀的想法就是窮舉,把陣列中元素的所有組合情況都找出來,然後看看哪些組合滿足給定的和即可,這種...
用回溯法解決八皇后問題 C語言
問題描述 要求在8x8的西洋棋棋盤上放入八個皇后,使得任意兩個皇后不能處於同一列,同一行,同一條斜線上。演算法思路 1 判斷皇后之間有沒有衝突,要引入四個量 row 行號,也對應於皇后的編號 column 列號 slash 斜線方向 bslash 反斜線方向 2 由棋盤的布局可以發現,在斜線方向上有...