问题描述
给定𝑛种物品和一个背包。物品𝑖的重量是𝑊𝑖,其价值为𝑉𝑖,背包的容量为C,应如何 选择装入背包的物品使得装入背包中物品的总价值最大? 这里,在选择物品𝑖装入背包时,可以选择物品𝑖的一部分,而不一定要全部装入背包。
输入
多组测试数据。每组测试包括三行:第一行输入物品的总数𝑛(𝑛 < 1000)和背包的容量 𝐶(𝐶 < 1000)。第二行输入𝑛个整数,表示物品的重量。第三行输入物品的价值。
输出
输出装入背包的总价值,每组测试数据输出一行。
Input
3 50
10 20 30
60 100 120
Output
240
思路
题目要求可以选某个物品的一部分装入背包,则我们可以将背包全部装满,而和01背包不一样的地方就是这里。
分析题目给出样例:
思路1.对价值最大的物品贪心,则是选择第2和第3件物品装入背包,总重量为50,总价值为220;
思路2.对体重最小的物品贪心,则是选择第1件和第2件物品和第三件物品的三分之二((50-10-20)/30)装入背包,总重量为50,总价值为240;
思路3.对价值率(价值除以重量)最大贪心,排序后就是1,2,3,然后对其进行贪心,选择第1件和第2件物品和第三件物品的三分之二((50-10-20)/30)装入背包,总重量为50,总价值为240;
这个样例很巧思路2和思路3得出的结果是一样的,
那么在来看一看下面这个数据。
3 20
18 15 10
25 24 15
(x1,x2,x3) | 总容量 | 总价值 | |
---|---|---|---|
思路1 | (1, 2/15, 0) | 20 | 28.2 |
思路2 | (0, 2/3, 1) | 20 | 31 |
思路3 | (0, 1, 1/2) | 20 | 31.5 |
所以我们采取第三种思路来做这个题,解题步骤如下:
1.对价值率进行降序;
2.依次选取物品,直到背包容量已满。
下面附上两个代码,第一个是对数据量小的,第二个对数据量较大的。
代码一
#include<stdio.h>
#define MaxSize 1000
typedef struct Node{
int wight,value;
double valueRate;
}node;
void InsertSort(int n,node *arr){
for(int i=1;i<n;i++){
node temp=arr[i];
int j=i;
while(j>0 &&temp.valueRate>arr[j-1].valueRate){
arr[j]=arr[j-1];//小数往后移
j--;
}
arr[j]=temp;
}
}
void SelectionSort(int n,node *arr){
for(int i=0;i<n-1;i++){
int mx=i;
for(int j=i+1;j<n;j++)
if(arr[mx].valueRate<arr[j].valueRate)
mx=j;
node temp=arr[mx];
arr[mx]=arr[i];
arr[i]=temp;
}
}
double solve(int n,int C,node *arr){
InsertSort(n,arr);//利用插入排序,对价值率从高到低排序,实行贪心
//SelectionSort(n,arr);//利用选择排序,对价值率从高到低排序,实行贪心
double ans=0;
for(int i=0;i<n;i++){
if(C>=arr[i].wight){//对价值率贪心,把能去满的物品直接取完
ans+=arr[i].value;//背包价值增加这个物品的价值
C-=arr[i].wight;//背包容量减少这个物品的重量
}
else{//不能去完的物品,说明背包是最后容纳的某个物品的一部分
ans+=(double)C/arr[i].wight*arr[i].value;
break;
}
}
return ans;
}
int main(){
int n,C;
puts("输入物品个数n和背包容量C");
scanf("%d%d",&n,&C);
node arr[n];
printf("输入%d个物品的重量\n",n);
for(int i=0;i<n;i++) scanf("%d",&arr[i].wight);
printf("输入%d个物品的价值\n",n);
for(int i=0;i<n;i++){
scanf("%d",&arr[i].value);
arr[i].valueRate=(double)arr[i].value/arr[i].wight;//算出价值率
}
double ans=solve(n,C,arr);
printf("最终背包所装的最大价值为:%.1f",ans);
return 0;
}
/*
3 20
18 15 10
25 24 15
3 50
10 20 30
60 100 120
*/
方法二:
#include<stdio.h>
#include<algorithm>
#define MaxSize 1000
using namespace std;
typedef struct Node{
int wight,value;
double valueRate;
}node;
bool cmp(node a,node b){//自定义比较函数
return a.valueRate>b.valueRate;
}
double solve(int n,int C,node *arr){
double ans=0;
for(int i=0;i<n;i++){
if(C>=arr[i].wight){//对价值率贪心,把能去满的物品直接取完
ans+=arr[i].value;//背包价值增加这个物品的价值
C-=arr[i].wight;//背包容量减少这个物品的重量
}
else{//不能去完的物品,说明背包是最后容纳的某个物品的一部分
ans+=(double)C/arr[i].wight*arr[i].value;
break;
}
}
return ans;
}
int main(){
int n,C;
puts("输入物品个数n和背包容量C");
scanf("%d%d",&n,&C);
node arr[n];
printf("输入%d个物品的重量\n",n);
for(int i=0;i<n;i++) scanf("%d",&arr[i].wight);
printf("输入%d个物品的价值\n",n);
for(int i=0;i<n;i++){
scanf("%d",&arr[i].value);
arr[i].valueRate=(double)arr[i].value/arr[i].wight;//算出价值率
}
sort(arr,arr+n,cmp);//对价值率从高到低排序,实行贪心
double ans=solve(n,C,arr);
printf("最终背包所装的最大价值为:%.1f",ans);
return 0;
}
/*
3 20
18 15 10
25 24 15
3 50
10 20 30
60 100 120
*/