背包问题分为很多种,其核心不过是寻找全部解或最优解的问题。
这篇文章就其中一个典型问题进行讲解。
题目:一个容积为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;
}