1. 程式人生 > >ACM知識點 之 貪心(4)部分揹包問題

ACM知識點 之 貪心(4)部分揹包問題

部分揹包問題雖說是歸於揹包問題的一種,而且揹包問題大多數是通過動態規劃的出的結果,但是貪心演算法解部分揹包,不管是思想還是操作上來說,都是非常簡單的。

首先,我們來看一下什麼叫做部分揹包。

有N個商品,每個商品的重量為WI,價格為:PI,現有一個揹包,最多能裝M的重量. 
其中(0<=I< N,0< wi<.M). 
問:怎樣裝能使包中裝入的商品價值最高(對於每個商品可以只裝該商品的一部分)

那我們就來分析一下條件:: 
1. 商品重量不是無限的。

    那就說明我們不能只拿一種東西,大多數情況都要進行多個物品的選取。

2. 商品可以被拆分成部分。

    那就說明我們需要考慮的不僅是“這個物品能不能裝”?,還要考慮“裝多少”?
    在這兩種情況下,我們需要考慮的是不能是物品的價值,而是價效比。

3. 商品的屬性有兩個:重量和價格;

    根據這兩個屬性,我們可以計算出商品的價效比,也就是單價。

4. 要求裝入揹包中的物品價格最高

    那就是說,我們需要按照價效比從高到低的順序進行,依次裝入我們需要得物品,直到揹包裝滿。
    由於是按照價效比從高到低的順序進行的選取,那麼同樣重量的揹包,這種方法獲得的價值是所有方法中最大的。

所以我們可以大概寫出偽程式碼表示整個求解過程:

sort 先把各個物品按照單價從高到低排序

for(迴圈每一個物品)
{
    if(物品的重量小於揹包剩餘的重量)
    {
        揹包剩餘的重量 -= 物品總重量;
        總價值 += 物品總價值;
    }else
    {
        總價值  += 物品單價*揹包剩餘重量;
        退出迴圈;
    }
}

                            揹包問題
                時間限制: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。

輸出 
輸出每組測試資料中揹包內的物品的價值和,每次輸出佔一行。

樣例輸入 

3 15 
5 10 
2 8 
3 9

樣例輸出 
65

和之前的分析過程一樣,而且這道題直接給的單價,所以更方便,直接上程式碼:

/*
************************************
    Title: NYOJ 106-揹包問題
************************************
    Date:2015/07/23
************************************
    author:劉旭
************************************
Memory:232KB
Time:0ms
************************************
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAX 105

struct Node
{
    int w;
    int v;
};

Node map[MAX];

bool cmp(Node a,Node b)
{
    if(a.v != b.v)
    {
        return a.v > b.v;
    }

    return a.w > b.w;
}

int main()
{
    int T = 0;
    scanf("%d", &T);
    while(T--)
    {
        memset(map, -1, sizeof(map));
        int num = 0;
        int weight = 0;
        scanf("%d%d", &num, &weight);

        for(int i = 0; i < num; i++)
        {
            scanf("%d%d", &map[i].v, &map[i].w);
        }

        sort(map, map+num, cmp);

        int ans = 0;

        for(int i = 0; i < num; i++){
            if(weight >= map[i].w){
                weight -= map[i].w;
                ans += map[i].v * map[i].w;
            }else{
                ans += map[i].v * weight;
                break;
            }
        }

        printf("%d\n", ans);

    }

    return 0;
}