1. 程式人生 > >揹包問題之一(回溯法)

揹包問題之一(回溯法)

揹包問題分為很多種,其核心不過是尋找全部解或最優解的問題。

這篇文章就其中一個典型問題進行講解。

題目:一個容積為T的揹包,和n件體積不等的物品,選出若干件物品剛好裝滿揹包,列出所有的組合。

顯然回溯法可以解決這個問題。回溯法是一種選優搜尋法,又稱為試探法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,迷宮問題是這種方法最直觀典型的應用。

首先要藉助一個數組儲存全部物品,一個vector儲存一組滿足條件物品,再寫一個遞迴呼叫的函式selectgood(int rest, int position), rest是揹包剩餘的容積,position代表當前搜尋的位置。當搜尋到currentposition時,假設此時揹包剩餘容積為currentrest,那麼有兩種情況,一種是選擇不將當前物品放入揹包,則呼叫函式selectgood(currentrest, currentposition+1),另一種情況是將當前物品放入揹包,但是在這種情況裡如果當前物品的體積大於currentrest,則不能繼續,如果不大於,則將當前物品放入vector,再判斷當前的rest,若揹包恰好裝滿,則輸出當前vector裡面的一組,若還未裝滿,則呼叫selectgood(currentrest,currentposition+1),最後當裝有當前物品的所有滿足情況輸出後,在函式最後將當前物品從vector取出。

程式碼:

#include<iostream>
#include<vector>
using namespace std;
int count = 0;
vector<int> mine;
int all[100];
int T, n;
void selectgood(int rest, int position) {
	if (rest == 0) return;
	if (position == n) return;
	selectgood(rest, position+1);
	if (rest < all[position]) return;
	mine.push_back(all[position]);
	if (rest == all[position]) {
		count++;
		vector<int>::iterator iter;
		for (iter = mine.begin(); iter != mine.end(); iter++) {
			cout << *iter << " ";
		}
		cout << endl;
	}
	selectgood(rest-all[position], position+1);
	mine.pop_back();
}
int main() {
	cin >> T >> n;
	for (int i = 0; i < n; i++) {
		cin >> all[i];
	}
	selectgood(T, 0);
	cout << "Totally " << count << " sets of solutions" << endl; 
}