题目描述
给定一个物品集合s={1,2,3,…,n},物品i的重量是wi,其价值是vi,背包的容量为W,即最大载重量不超过W。在限定的总重量W内,我们如何选择物品,才能使得物品的总价值最大。
输入
第一个数据是背包的容量为c(1≤c≤1500),第二个数据是物品的数量为n(1≤n≤50)。接下来n行是物品i的重量是wi,其价值为vi。所有的数据全部为整数,且保证输入数据中物品的总重量大于背包的容量。
当c=0时,表示输入数据结束。
输出
对每组测试数据,输出装入背包中物品的最大价值。
解题思路
代码
#include <iostream>
#include<bits/stdc++.h>
#define N 100
#define INF 0x3f3f3f3f
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(i,a,n) for(int i=a;i<=n;i++)
typedef long long ll;
using namespace std;
#define NUM 100
int c;//背包的容量
int n;//物品的数量
int cw;//当前重量
int cv;//当前价值
int bestv;//当前最优价值
//描述每个物品的数据结构
struct Object
{
int w;//物品的重量
int v;//物品的价值
double d;//物品的单位重量价值比
}Q[NUM]; //物品的数组
bool cmp(Object a, Object b)
{
if(a.d>=b.d) return true;//按性价比从大到小
else return false;
}
//形参i是回溯的深度
int Bound(int i)
{
int cleft = c-cw;//背包剩余的容量
int b = cv;//上界
//尽量装满背包
while(i<n && Q[i].w<=cleft)
{
cleft -= Q[i].w;
b += Q[i].v;
i++;
}
//剩余的部分空间也装满
if (i<n)
b += 1.0*cleft*Q[i].v/Q[i].w;
return b;
}
//i从0开始
void backtrack(int i)
{
//到达叶子结点时,更新最优值
if (i+1>n)
{
bestv = cv;
return;
}
//进入左子树搜索
if (cw+Q[i].w<=c)
{
cw += Q[i].w;
cv += Q[i].v;
backtrack(i+1);
cw -= Q[i].w;
cv -= Q[i].v;
}
//进入右子树搜索
if (Bound(i+1)>bestv)
backtrack(i+1);
}
int main()
{
cin>>c>>n;
for(int i=0; i<n; i++)
{
cin>>Q[i].w>>Q[i].v;
if(Q[i].w==0)break;
Q[i].d = 1.0*Q[i].v/Q[i].w;//转换为浮点型再除
}
sort(Q,Q+n,cmp);
backtrack(0);
cout<<bestv<<endl;
}