#部分背包问题 #贪心算法
题目
题目来源 - https://www.luogu.com.cn/problem/P2240
深基12.例1 部分背包问题
题目描述
阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N ( N ≤ 100 ) N(N \le 100) N(N≤100) 堆金币,第 i i i 堆金币的总重量和总价值分别是 m i , v i ( 1 ≤ m i , v i ≤ 100 ) m_i,v_i(1\le m_i,v_i \le 100) mi,vi(1≤mi,vi≤100)。阿里巴巴有一个承重量为 T ( T ≤ 1000 ) T(T \le 1000) T(T≤1000) 的背包,但并不一定有办法将全部的金币都装进去。他想装走尽可能多价值的金币。所有金币都可以随意分割,分割完的金币重量价值比(也就是单位价格)不变。请问阿里巴巴最多可以拿走多少价值的金币?
输入格式
第一行两个整数 N , T N,T N,T。
接下来 N N N 行,每行两个整数 m i , v i m_i,v_i mi,vi。
输出格式
一个实数表示答案,输出两位小数
样例 #1
样例输入 #1
4 50
10 60
20 100
30 120
15 45
样例输出 #1
240.00
代码
分析《深入浅出程序设计竞赛(基础篇)》
#include<cstdio>
#include<algorithm>
using namespace std;
struct coin{ // 结构体
int m,v; // 整型变量成员m,v 堆中金币的总重量和总价值
} a[110];
bool cmp(coin x,coin y){// 自定义函数 比较两堆金币的单位重量的价值
return x.v*y.m>y.v*x.m; // x堆的价值 * y堆的重量 > y堆的价值 * x堆的重量 》 v1/m1 > v2/m2 》 v1*m2 > v2*m1
}
int main(){
int n,t,c,i;
float ans =0;
scanf("%d%d",&n,&t); // 读入整型数据到n和t n堆金币 t重量容量的背包
c=t;// c等于背包的容量
for(i=0;i<n;i++){ // i》 0,1,2,...,n-1 》 从0开始遍历每一堆金币的数据
scanf("%d%d",&a[i].m,&a[i].v); // 读入整型数据重量,价值到 a[i] 堆中的m,v
}
sort(a,a+n,cmp);// 按cmp函数的规则(单位价值)排列金币堆
for(i=0;i<n;i++){// 按总堆数进行遍历 0..n
if(a[i].m>c){// 如果i堆的重量大于c则退出遍历
break;
}
c-=a[i].m; // 从c中减去i堆的重量
ans+=a[i].v;// ans中增加i堆的价值
}
if(i<n){// 如果没有遍历到最后一堆
ans+=1.0*c/a[i].m*a[i].v;// 1*c/im*iv 》 剩余容积/ i堆重量*i堆价值 》 容积* i堆价值/i堆重量 》容积*i堆单价
// 在ans中增加从i堆中取出放满背包的金币的价值。
}
printf("%.2lf",ans); // 输出背包中的金币的总价值
return 0;
}
/*
算法分析
1. 将金币堆按价值排序
2. 从单位重量价值最大的金币堆开始装包,直到整堆装不进去为止
3. 判断是否将所有金币都装包了,
3.1. 如果没有将未装包的第一堆(剩余单价最大的)中剩余背包容积的部分装包
4. 输出背包中金币的总价值
PS: 明显这个金币不是纯金。。。。
*/