背包问题贪心算法求解

题目

有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。
要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。
在这里插入图片描述

思路

具有最优子结构性质和贪心选择性质。只要是所有物品的总重量大于背包容纳量,那么背包一定能装满。注意背包问题与0-1背包问题的区别。
这2类问题都具有最优子结构性质,极为相似,但背包问题可以用贪心算法求解,而0-1背包问题却不能用贪心算法求解。

求解步骤

用贪心算法解背包问题的基本步骤:首先计算每种物品单位重量的价值v[i]/w[i],然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包。依此策略一直地进行下去,直到背包装满为止。

代码实现

#include <iostream>
using namespace std;
//按照单位重量的价值量大小降序排列
void Sort(int n,float *w,float *v)
{
    int i,j;
    float temp1,temp2;
    for(i=1;i<=n;i++)
    for(j=1;j<=n-i;j++)//冒泡排序
    {
        temp1=v[j]/w[j];
        temp2=v[j+1]/w[j+1];
        if(temp1<temp2)
        {
            swap(w[j],w[j+1]);
            swap(v[j],v[j+1]);
        }
    }
}
int main()
{
    float w[101];//用来表示每个物品的重量
    float v[101];//用来表示每个物品的价值量
    float x[101];//表示最后放入背包的比例
    int n;//物品数
    float M;//背包最大容纳重量
    cin>>n>>M;
    //依次输入每件物品的重量和价值量
    for(int i=1;i<=n;i++)
        cin>>w[i]>>v[i];
    //按照单位重量的价值量大小降序排列
    Sort(n,w,v);
    int i;
    for(i=1;i<=n;i++)
        x[i]=0;//初始值,未装入背包,x[i]=0
    float c=M;//更新背包容纳量
    for(i=1;i<=n;i++)
    {
        if(c<w[i])  break;//不能完全装下
        x[i]=1;
        c=c-w[i];
    }
    if(i<=n)
        x[i]=c/w[i];
    //输出
    for(int i=1;i<=n;i++)
        cout<<"重量为"<<w[i]<<"价值量为"<<v[i]<<"的物品"<<"放入的比例为"<<x[i]<<endl;
    return 0;
}

在这里插入图片描述

算的主要计算时间在于将各种物品依其单位重量的价值从大到小排序。因此,算法的计算时间上界为O(nlogn)。
为了证明算法的正确性,还必须证明背包问题具有贪心选择性质。

对于0-1背包问题,贪心选择之所以不能得到最优解是因为在这种情况下,它无法保证最终能将背包装满,部分闲置的背包空间使每公斤背包空间的价值降低了。事实上,在考虑0-1背包问题时,应比较选择该物品和不选择该物品所导致的最终方案,然后再作出最好选择。由此就导出许多互相重叠的子问题。这正是该问题可用动态规划算法求解的另一重要特征。
实际上也是如此,动态规划算法的确可以有效地解0-1背包问题。

### 贪心算法解决背包问题的具体方法 贪心算法通过每次选择当前最优解来逐步构建全局最优解。对于部分背包问题,其核心在于按照单位重量的价值(`value/weight`)对物品进行排序,并优先选取单位价值最高的物品放入背包,直到无法再装入整个物品为止。 #### 方法描述 1. **计算单位价值**:对于每个物品,计算其单位重量对应的价值 `wm = value / weight`[^3]。 2. **排序**:将所有物品按单位价值降序排列。如果采用归并排序,则时间复杂度为 \(O(n \log n)\)[^3]。 3. **填充背包**:依次尝试将物品加入背包: - 如果当前物品的重量小于等于剩余容量,则将其完全装入; - 否则,仅装入该物品的一部分以填满背包剩余空间[^1]。 --- ### Python 实现示例 以下是基于引用[2]的代码实现: ```python def knapsack_greedy(capacity, items): """ 使用贪心算法求解部分背包问题 :param capacity: 背包最大承重 (int) :param items: 列表 [(weight, value), ...] 表示每件物品的重量和价值 :return: 返回最终选中的物品列表及其总价值 """ # 按照单位价值(value/weight)降序排序 items_sorted = sorted(items, key=lambda x: x[1]/x[0], reverse=True) total_value = 0 # 总价值 selected_items = [] # 已选物品记录 for item in items_sorted: if capacity >= item[0]: # 当前物品可全部装下 selected_items.append((item[0], item[1])) total_value += item[1] capacity -= item[0] elif capacity > 0 and item[0] != 0: # 部分装载当前物品 fraction = capacity / item[0] partial_value = fraction * item[1] selected_items.append((capacity, partial_value)) total_value += partial_value break # 背包已满 return selected_items, round(total_value, 2) # 测试数据 items = [ (10, 60), # 物品1: 重量10kg, 价值60元 (20, 100), # 物品2: 重量20kg, 价值100元 (30, 120) # 物品3: 重量30kg, 价值120元 ] knapsack_capacity = 50 result = knapsack_greedy(knapsack_capacity, items) print("选中物品:", result[0]) print("总价值:", result[1]) ``` 运行以上代码的结果如下: - 输入背包容量为 50 kg 的情况下, - 输出为 `(选中物品: [(10, 60), (20, 100), (20, 80)], 总价值: 240)`[^2]。 --- ### 解析与验证 上述程序的核心逻辑是对物品按单位价值排序后逐一处理。当遇到无法完全装下的情况时,会根据剩余容量比例分配部分价值[^1]。此过程确保了在任何时刻都选择了局部最优解,从而达到整体效益最大化的目标。 ---
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值