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

貪心算法經典應用三:背包問題與 0-1 背包的 C 語言實現及最優性差異分析

     編輯:關於C語言

問題定義

給定 n 種物品,第 i 種物品重量 w[i],價值 v[i];背包容量為 c。目標是選擇物品裝入背包,使總價值最大。根據物品是否可分割,分為兩類:

  • 分數背包問題:物品可任意分割,可裝入部分。
  • 0-1 背包問題:物品不可分割,只能整件裝入或不裝。

貪心策略的度量標準選擇

面對多維度屬性(價值、重量),貪心算法需確定單一決策指標:

度量標準缺點
單純價值 v[i]高價值物品可能過重,導致裝入極少
單純重量 w[i]輕物品價值可能極低,浪費容量
單位價值 v[i]/w[i]綜合考量「性價比」,為最優指標

因此,貪心策略為:按單位價值由高到低排序,依序裝入。

演算法流程

  1. 計算所有物品單位價值 v[i]/w[i];
  2. 按單位價值非遞增排序;
  3. 依序嘗試裝入:
        - 分數背包:若剩餘容量不足裝下整件,裝入該物品的一部分(比例 = 剩餘容量 / 物品重量),背包滿即停止。
        - 0-1 背包:若剩餘容量不足裝下整件,直接跳過該物品,嘗試下一件;直到所有物品處理完畢或背包無法裝入任何剩餘物品。

C 語言完整實現

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

void package(int n, float c, float v[], float w[], float x[]);
void package0_1(int n, float c, float v[], float w[], float x[]);

int main(void) {
    int n = 3;
    float c = 20;
    float v[] = {24, 15, 25};
    float w[] = {15, 10, 18};  // 已按單位價值降序:1.6, 1.5, 1.388...
    float *x = (float*)malloc(sizeof(float) * n);

    printf("****** 分數背包 *******\n");
    package(n, c, v, w, x);
    printf("******* 0-1 背包 ******\n");
    package0_1(n, c, v, w, x);
    system("PAUSE");
    free(x);
    return 0;
}

/* 分數背包:可裝入部分物品 */
void package(int n, float c, float v[], float w[], float x[]) {
    int i;
    for (i = 0; i < n; i++) x[i] = 0.0;

    for (i = 0; i < n; i++) {
        if (w[i] > c) break;          // 無法裝下整件
        x[i] = 1.0;                   // 整件裝入
        c -= w[i];
        printf("放入第%d件物品,背包剩餘容量 %.2f\n", i+1, c);
    }
    if (i < n) {                      // 還有物品且背包未滿,裝入部分
        x[i] = c / w[i];
        printf("放入第%d件物品的 %.2f 部分,背包剩餘容量 0\n", i+1, x[i]);
    }
}

/* 0-1 背包:只能整件裝入或不裝 */
void package0_1(int n, float c, float v[], float w[], float x[]) {
    int i;
    for (i = 0; i < n; i++) x[i] = 0.0;

    for (i = 0; i < n; i++) {
        if (w[i] > c) break;          // 無法裝下整件,跳過
        x[i] = 1.0;
        c -= w[i];
        printf("放入第%d件物品,背包剩餘容量 %.2f\n", i+1, c);
    }
    // 無法裝入部分物品,循環結束即為最終方案
}

關鍵差異與最優性分析

分數背包:貪心得最優解 ✓

分數背包具有貪心選擇性質:局部最優的單位價值選擇能推導出全域最優。證明核心在於「可分割性」消除了殘餘容量浪費,任何非貪心方案都可通過調整向貪心方案靠攏而不降低總價值。

0-1 背包:貪心不保證最優解 ✗

0-1 背包中,物品不可分割導致殘餘容量可能無法被利用。貪心策略雖選了高性價比物品,但可能留下「裝不下任何剩餘物品」的碎片空間,導致總價值低於最優解。

反例演示

容量 c=20,物品:

  • A: w=18, v=25 (單位價值 1.389)
  • B: w=10, v=15 (單位價值 1.5)
  • C: w=15, v=24 (單位價值 1.6) —— 貪心首選

貪心解:選 C (w=15, v=24),剩餘 5 無法裝入 A 或 B → 總價值 24。

最優解:選 A + B (w=18+10=28>20 不行) → 實際最優為 B 兩件?但 0-1 只能各一件。重新構造:

  • 物品1: w=10, v=60 (單位6.0)
  • 物品2: w=20, v=100 (單位5.0)
  • 物品3: w=30, v=120 (單位4.0)

容量 50。貪心選 1+2 (w=30, v=160),剩20裝不下3。最優解為 2+3 (w=50, v=220)。

總結與啟示

問題類型貪心策略是否最優最優解法
分數背包按單位價值排序是貪心 O(n log n)
0-1 背包按單位價值排序否(近似解)動態規劃 O(nc)

這對經典對比深刻揭示了:問題結構(可分割性)決定了貪心算法的有效性。工程實踐中,若遇到 0-1 背包類問題,必須採用動態規劃、分支限界或近似算法,而非單純貪心。

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