部分背包问题-贪心算法

部分背包问题-贪心算法

问题描述

有一个调制饮品比赛

  • 参赛者拥有容量为 c ml的杯子,可任选不超过体积上限的饮料进行混合
  • 调制饮品价格为各所使用饮料的价格之和,所得饮品价格之和最高者获胜

每种饮品有对应的价值和体积,应该如何使调制的饮品价格最高?

输入数据

第一行输入物品数量n和背包容量c。
接下来是n行数据,表示每个饮料的价值的体积。

输入输出样例

输入:

5 800
60 600
10 250
36 200
16 100
45 300

输出:

117

思路分析

这是一个典型的贪心问题,要求调制的饮品价格最高。
我们采用最高性价比优先的方法

  • 性价比 = 价格/体积
  • 优先选择高性价比饮料全部装入,尽可能装满杯子

首先对n种饮品按照性价比降序排序,这里对于饮品我使用了结构体类型,结合sort函数即可实现。
定义一个ans表示当前饮品的价值,并赋初值为0,接下来对排好序的饮品进行遍历循环,循环条件为c>0(杯子还有剩余体积)且i<n.
while循环体内,若当前饮品体积小于剩余体积c,则将其全部放入,c=c-当前饮品体积;
否则,放入剩余体积c的该饮品,也就是将剩下的体积全部放入当前饮品,c=0。

代码样例

//
//  main.cpp
//  部分背包问题
//
//  Created by MacBook Pro on 2021/4/19.
//

#include <iostream>
#include<algorithm>
using namespace std;
struct goods//表示商品
{
    float weight;//重量
    float value;//价值
    float ratio;//性价比
};
bool cmp(goods x,goods y)
{
    return x.ratio>y.ratio;
}
int FractionalKnapsack(int n,goods a[],int c)//求解背包问题
{
    sort(a,a+n,cmp);//按照性价比降序排序
    int ans=0;
    int i=0;
    while(c>0&&i<n)
    {
        if(a[i].weight<=c)//选择商品i的全部
        {
            ans+=a[i].value;
            c-=a[i].weight;
        }
        else//选择剩余c体积的商品i
        {
            ans+=a[i].value*(c/a[i].weight);
            c=0;
        }
        i++;
    }
    return ans;
}
int main()
{
    int n,i,c; //c为背包容量
    cin>>n>>c;
    goods a[n];//定义结构体数组
    for(i=0;i<n;i++)
    {
        cin>>a[i].value>>a[i].weight;
        a[i].ratio=(float)a[i].value/(float)a[i].weight;//ratio=value/weight
    }
    cout<<"最优解为"<<FractionalKnapsack(n,a,c)<<endl;
    return 0;
}