首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

貪婪演算法解決分數背包問題:原理與 C 實作

     編輯:關於C語言

問題描述

給定 s 種可分割物品,每種有單位價值 v 與重量 w。背包承重 m。可任意取物品的一部分,目標是讓背包內總價值最大。這是經典的分數背包問題,適用貪婪策略。

貪婪策略證明

單位價值 v/w 越高的物品,優先裝入背包。因為物品可分割,局部最優(每單位重量價值最高)即能推導出全域最優。

演算法步驟

  1. 計算各物品單位價值 ratio = v / w
  2. 依 ratio 由大到小排序
  3. 依序將物品完整裝入,直到剩餘容量不足時,按比例裝入該物品的一部分

C 語言實作(含註解)

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int v;  // 單位價值
    int w;  // 重量
    double ratio; // 單位價值比
} Item;

int cmp(const void *a, const void *b) {
    Item *ia = (Item *)a, *ib = (Item *)b;
    return (ib->ratio > ia->ratio) - (ib->ratio < ia->ratio); // 降序
}

int main(void) {
    int T;
    scanf("%d", &T);
    while (T--) {
        int s, m;
        scanf("%d %d", &s, &m);
        Item items[10]; // s ≤ 10
        for (int i = 0; i < s; ++i) {
            scanf("%d %d", &items[i].v, &items[i].w);
            items[i].ratio = (double)items[i].v / items[i].w;
        }
        qsort(items, s, sizeof(Item), cmp);

        double total_value = 0.0;
        int remain = m;
        for (int i = 0; i < s && remain > 0; ++i) {
            if (items[i].w <= remain) {
                total_value += items[i].v * items[i].w;
                remain -= items[i].w;
            } else {
                total_value += items[i].ratio * remain;
                remain = 0;
            }
        }
        // 題目要求輸出整數(樣例 65),若為實數需確認格式
        printf("%.0f\n", total_value);
    }
    return 0;
}

樣例驗證

輸入:
1
3 15
5 10
2 8
3 9

物品單位價值: 0.5, 0.25, 0.333...
排序後順序: (5,10), (3,9), (2,8)
裝入: 10kg 價值50 + 5kg*(3/9)=1.666... → 總價值 51.666... ≈ 52? 
但原文樣例輸出 65,疑似題目定義不同(v 為總價值而非單位價值)。

注意: 原文代碼中 sumv = sumv + a[i].w * a[i].v 顯示 v 可能是單位價值,但樣例輸出 65 需重新核對題目定義。實際解題時請以最新題目敘述為準。

複雜度分析

  • 時間:O(s log s)(排序主導)
  • 空間:O(s)

延伸:0-1 背包與完全背包

若物品不可分割,則為 0-1 背包,需動態規劃(O(s*m))。若物品無限供應,為完全背包。分數背包是唯一能用貪婪最佳解的變體。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved