背包问题
题目来自南阳理工OJ
背包问题
时间限制:3000 ms | 内存限制:65535 KB
难度:3
描述
现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v,w<=10);如果给你一个背包它能容纳的重量为m(10<=m<=20),你所要做的就是把物品装到背包里,使背包里的物品的价值总和最大。
输入
第一行输入一个正整数n(1<=n<=5),表示有n组测试数据;
随后有n测试数据,每组测试数据的第一行有两个正整数s,m(1<=s<=10);s表示有s个物品。接下来的s行每行有两个正整数v,w。
输出
输出每组测试数据中背包内的物品的价值和,每次输出占一行。
样例输入
1
3 15
5 10
2 8
3 9
样例输出
65
问题分析
学动态规划时我们已经了解了三种最基本的背包问题:零一背包,部分背包,完全背包。很容易证明,背包问题不能使用贪心算法。
然而我们考虑这样一种背包问题:在选择物品i装入背包时,可以选择物品的一部分,而不一定要全部装入背包。这时便可以使用贪心算法求解了。计算每种物品的单位重量价值作为贪心选择的依据指标,选择单位重量价值最高的物品,将尽可能多的该物品装入背包,依此策略一直地进行下去,直到背包装满为止。
在零一背包问题中贪心选择之所以不能得到最优解原因是贪心选择无法保证最终能将背包装满,部分闲置的背包空间使每公斤背包空间的价值降低了。注意因为元素被分割开了,所以这里可能要用double,应该根据题目描述处理。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<functional>
#include<utility>
using namespace std;
struct Pair{
int first;
int second;
};
int n, s, m, v, w;
const int maxn=100001;
Pair pack[maxn];
int sum=0;
bool cmp( const Pair &x,const Pair &y)
{
return x.first > y.first;
}
int main()
{
cin>>n;
while(n--)
{
scanf("%d%d",&s,&m);
sum=0;
for(int i=1;i<=s;i++)
{
pack[i].first=0;
pack[i].second=0;
}
for(int i=1;i<=s;i++)
{
scanf("%d%d",&v,&w);
pack[i].first=v;
pack[i].second=w;
}
// for(int i=1;i<=s;i++) printf("%d\t%d\n",pack[i].first,pack[i].second);
sort( pack+1,pack+s+1,cmp);
// for(int i=1;i<=s;i++) printf("%d\t%d\n",pack[i].first,pack[i].second);
int i;
for(i=1;i<=s;i++)
{
if(pack[i].second > m) break;
else
{
sum+=pack[i].first*pack[i].second;
m-=pack[i].second;
}
}
if(i <= s) sum+=pack[i].first*m;
printf("%d\n",sum);
}
return 0;
}