参考
概述
有n个物品重量分别为(),能否从这n个物品中挑选若干物品使重量为T。若有解给出全部解
思路
因为要是有解则给出全部解。
dfs,回溯法。解空间:每个东西取或者不取两种情况。剪枝函数:当>=的时候返回。
怎么描述这个解呢?比如说有一个背包,里面有物品重量为,{2,3,5,4},那么对第i个物品有取(1)或者不取(0)两种情况。解空间如下
这里只画到了第三层。
可以看到,到了每一层,要做的事情都是相同的。拿画圆圈的那一个为例子,假设之前的数组中已经存了01,那么接下来要做的事情是:1.判断(相当于一个剪枝函数)。看看当前物品总重量。当前背包总重量为3,要是超过了要求的总重量,那么此路不通,return;要是等于要求的总重量,那么得到结果,输出当前的结果,return;要是小于要求的总重量,那么还需要继续确定下一个物品取或者不取。2.确定取,或者不取两种情况。并确定数组的下一个数字为1或者0.那么新数组为010,011.把这两个数组传入递归函数,再次进行同样的操作。
code
#include<stdio.h>
#include<iostream>
#define SIZE 8
using namespace std;
int num = 1;
void get(int bag[], int result[], int T, int i);//确定当前第i个位置
void print(int result[]);//打印结果
int main()
{
int bag[SIZE] = {2, 4, 1, 3, 1, 5, 2, 8};
int result[SIZE] = {0};
int T = 10;
get(bag, result, T, 0);
return 0;
}
void get(int bag[], int result[], int T, int i)
{
//返回条件
if(T == 0)
{
print(result);//输出结果
}
//如果如果超出去了,或者全选完了,返回
else if(T < 0 || i == SIZE)
{
return;
}
else
{
//不取
result[i] = 0;
get(bag, result, T, i + 1);
//取
result[i] = 1;
get(bag, result, T - bag[i], i + 1);
}
}
void print(int result[])
{
int i;
cout<<"第"<<num<<"组:";
for(i = 0; i < SIZE; i++){
if(result[i] == 1)
{
cout<<i<<" ";
}
}
cout<<endl;
num++;
}
不知道为什么会出现奇奇怪怪的结果,貌似进行下一种的时候result数组中还存着前面的结果。
试着在每次达到目标之后把result后面还没有遍历的值都赋0,就解决了这个问题。但是result是什么时候改变的呢?
while(i < SIZE){
result[i] = 0;
i++;
}
加上了上面这段代码后结果对比
可以看出来应该答案是找对了的,但是result后面还没遍历的项为啥是1呢?
问题出在,在调用了get(bag, result, T, i + 1);
之后,result数组i+1后面的值已经改变了,我还以为没改。所以这个时候要把result后面的值重新赋0.
所以在两个get()函数之间加入这段代码即可
int k = i;
while(k < SIZE){
result[k] = 0;
k++;
}