2629: 回溯法-01背包问题
金币值:3
定数:7
时间限制:1.000 s
内存限制:128 M
正确:4
提交:4
正确率:100.00% 命题人:
题目描述
给定n(1<=n<=20)种物品和一背包,物品i (1≤i≤n) 的重量是wi (wi > 0),其价值为vi (vi > 0),背包的容量为c, 问应如何选择装入背包的物品,使得装入背包中物品的总价值最大? 为了方便编写限界函数,假设按照单位重量获利递减输入每个物品的重量和获利。
测试代码 复制
#include <stdio.h>
// 为了方便编写限界函数,假设按照单位重量获利递减输入每个物品的重量和获利。
int w[21]; //存储物品重量,0号单元不存储有效数据
int v[21]; //存储物品价值,0号单元不存储有效数据
int n;//存储物品个数
int c;//存储背包容量
int bestx[21]; //最优解,0号单元不存储有效数据
int x[21]; //当前解,0号单元不存储有效数据
int bestv;//最优值
int cv;//当前已经放到背包中的物品价值
int cw;//当前已经放到背包中的物品重量
double bound(int i) { //计算剩余物品(i:n)的上界
int cleft=c-cw; // 剩余容量
int b=0; // b是一个临时变量
while(i<=n && w[i]<=cleft) {
cleft-=w[i];
b+=v[i];
i++;
}
if (i<=n) {
b+=1.0*v[i]/w[i]*cleft; // 装满背包
}
return b;
}
void backtrack(int i) { // 搜索第i层结点
if(i>n) { //到达叶结点考虑结束本次递归
} else {
if(cw+w[i]<=c) { //搜索左子树,此时必须满足约束函数
}
if (cv+bound(i+1)>bestv) { //搜索右子树,使用限界函数的目的是为了剪枝,提高算法效率;此处也可以不考虑限界函数。
}
}
}
int main(void) {
scanf("%d %d",&n,&c);
for(int i=1; i<=n; i++) {
scanf("%d",&w[i]);
}
for(int i=1; i<=n; i++) {
scanf("%d",&v[i]);
}
cw=0;
cv=0;
backtrack(1);
printf("%d\n",bestv);
for(int i=1; i<=n; i++) {
printf("%d ",bestx[i]);
}
return 0;
}
输入格式
第一行输入两个整数,分别表示n个物品和背包容量c
第二行输入n个整数,分别表示每个物品的重量
第三输入n个整数,分别表示每个物品的价值
第二行输入n个整数,分别表示每个物品的重量
第三输入n个整数,分别表示每个物品的价值
输出格式
第一行输出最大价值
第二行输出最解向量的值(1表示放入背包,0表示没有放入背包)
第二行输出最解向量的值(1表示放入背包,0表示没有放入背包)
输入样例 复制
3 10
3 4 5
4 5 6
输出样例 复制
11
0 1 1