貪心算法:部分背包問題深度解析

簡介:

該Java代碼基于貪心算法實現了分數背包問題的求解,核心通過單位價值降序排序和分階段裝入策略實現最優解。首先對Product數組執行雙重循環冒泡排序,按wm(價值/重量比)從高到低重新排列物品;隨后分兩階段裝入:循環完整裝入單位價值最高的物品直至剩余容量不足,最后計算部分裝入比例并累加殘值。代碼突出展現了貪心算法的"局部最優推導全局最優"特性,通過預排序確保每次選擇當前最優物品,其O(n2)排序過程與線性裝入流程共同構成算法主體,物品裝入狀態數組和DecimalFormat精度控制體現實用性。(注:當前排序邏輯存在i,j均從1開始遍歷的非常規冒泡實現,可能需優化為標準冒泡或更高效的排序算法)

貪心算法(Greedy Algorithm)

定義:一種在每一步選擇中都采取當前狀態下最優(即最有利)的決策,從而希望導致結果是全局最優的算法策略。

核心特征

  1. 局部最優性:每個決策步驟都選擇當前最佳選項
  2. 不可回溯性:做出的選擇不可更改
  3. 高效性:通常時間復雜度低于動態規劃

適用條件

  • 問題具有最優子結構(全局最優包含局部最優)
  • 問題具有貪心選擇性質(局部最優能推導全局最優)

典型應用場景

  1. 部分背包問題(當前案例)
  2. 霍夫曼編碼
  3. 最小生成樹(Prim/Kruskal算法)
  4. 最短路徑(Dijkstra算法)

在部分背包中的體現

// 按單位價值降序排列(核心貪心策略)
if(products[i].wm > products[j].wm) { ... }

優缺點對比

優勢局限性
時間復雜度低(O(n2))不能保證所有問題的最優解
實現簡單直觀依賴問題特性(需證明正確性)
空間復雜度低(O(n))選擇策略設計難度較高

題目:

注意:題目中的排序方法使用的是:歸并排序

一、核心代碼逐行解析

1. 數據結構定義(Product類)

class Product {int w;    // 物品實際重量int v;    // 物品完整價值double wm; // 單位重量價值(v/w)public Product(int w, int v) {this.w = w;this.v = v;// 計算單位價值(保留兩位小數)this.wm = Double.parseDouble(new DecimalFormat("#.00").format((double)v/w));// 處理邊界條件if(w == 0 || v == 0) this.wm = 0;}
}

執行流程說明

  • w=40, v=40wm=1.00
  • w=50, v=60wm=1.20
  • w=20, v=30wm=1.50

2. 核心算法實現

// 階段1:完整物品裝入
int i = 1;
while(W >= products[i].w) {  // 剩余容量 >= 當前物品重量weight += products[i].w;  // 累加已裝重量result += products[i].v;  // 累加總價值W -= products[i].w;       // 更新剩余容量items[i] = 1;             // 標記完全裝入i++;                      // 指向下個物品
}// 階段2:部分物品裝入
result += products[i].wm * W;   // 按比例計算剩余價值
items[i] = (double)W/products[i].w; // 記錄裝入比例

執行示例
初始容量W=100:

  1. 裝入物品3(w=20)→ W=80
  2. 裝入物品5(w=30)→ W=50
  3. 裝入物品2(w=50)→ W=0
    最終剩余容量處理:無

二、算法流程圖解

完整執行流程

graph TDA[初始化物品數據] --> B[計算單位價值wm]B --> C{排序檢查}C -->|i=1| D[比較products[i]與products[j]]D -->|wm更大| E[交換物品位置]E --> F{完成排序?}F -->|否| CF -->|是| G[循環裝入完整物品]G --> H{容量足夠?}H -->|是| I[完整裝入]H -->|否| J[計算部分裝入]J --> K[輸出結果]

時間復雜度分解

三、關鍵算法深度解析

1. 排序算法實現

public static void sortProducts(Product[] products, int N) {for(int i=1; i<=N; i++) {        // 控制排序輪次for(int j=1; j<=N; j++) {    // 執行元素比較if(products[i].wm > products[j].wm) {// 元素交換三部曲Product temp = products[j];products[j] = products[i];products[i] = temp;}}}
}

算法特點

  • 典型冒泡排序變種
  • 時間復雜度:嚴格O(n2)
  • 空間復雜度:O(1)原地排序
  • 缺陷:存在冗余比較(每次全量遍歷)
優化代碼
// 優化后的冒泡排序實現
public static void sortProducts(Product[] products, int N) {for(int i = 1; i <= N-1; i++) { // 只需N-1輪比較boolean swapped = false;    // 交換標志位for(int j = 1; j <= N-i; j++) { // 每輪減少比較范圍if(products[j].wm < products[j+1].wm) { // 比較相鄰元素Product temp = products[j];products[j] = products[j+1];products[j+1] = temp;swapped = true;}}if(!swapped) break; // 提前終止優化}
}

2. 貪心策略實現

// 物品選擇數組初始化
double[] items = new double[N+1]; // 索引1~N存儲選擇比例// 完整物品標記
items[i] = 1; // 二進制式標記(0或1)// 部分物品計算
double ratio = (double)W/products[i].w; // 精確計算比例

數學原理
總價值 = Σ(完整物品v) + 剩余容量×max(wm)

四、完整實例代碼

import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Properties;public class Test2 {public static void main(String[] args) {int N=5; // 總數量int W=100;// 總容量double result =0.0;// 總價值double[] items =new double[N+1];Product[] products=new Product[]{new Product(0,0),new Product(40,40),new Product(50,60),new Product(20,30),new Product(10,20),new Product(30,65),};int weight =0;sortProducts(products,N);printProducts(products,N);int i =1;while(W>=products[i].w){weight+=products[i].w;result+=products[i].v;W -= products[i].w;items[i]=1;i++;}// 部分result+=products[i].wm*W;items[i]=(double) W/products[i].w;System.out.println(result);printItems(items,N);}
//    // 排序
//    public  static void sortProducts(Product[] products,int N) {
//        for(int i=1;i<=N;i++){
//            for( int j=1;j<=N;j++){
//                if(products[i].wm>products[j].wm){
//                    Product product=products[j];
//                    products[j]=products[i];
//                    products[i]=product;
//                }
//            }
//        }
//    }// 優化后的冒泡排序實現public static void sortProducts(Product[] products, int N) {for(int i = 1; i <= N-1; i++) { // 只需N-1輪比較boolean swapped = false;    // 交換標志位for(int j = 1; j <= N-i; j++) { // 每輪減少比較范圍if(products[j].wm < products[j+1].wm) { // 比較相鄰元素Product temp = products[j];products[j] = products[j+1];products[j+1] = temp;swapped = true;}}if(!swapped) break; // 提前終止優化}}public static void printProducts(Product[] pducts,int N){for (int i = 1; i <=N ; i++) {System.out.println(pducts[i]);}}public static void printItems(double[] items,int N){for (int i = 1; i <=N ; i++) {System.out.print(items[i]+" ");}System.out.println("");}}class Product{int w;// 重量int v;// 價值double wm;// 重量價值public Product(int w, int v) {this.w = w;this.v = v;this.wm =Double.parseDouble(new DecimalFormat("#.00").format((double) this.v/this.w));if(w==0 ||  v==0){this.wm =0;}}public Product(){}@Overridepublic String toString() {return "Product{" +"w=" + w +", v=" + v +", wm=" + wm +'}';}
}

運行結果:

五、復雜度分析進階

時間復雜度對比

排序算法時間復雜度本實現采用適用場景
冒泡排序O(n2)?教學示例
快速排序O(n logn)生產環境
堆排序O(n logn)大數據量

空間復雜度優化

// 原始實現
Product[] products = new Product[N+1]; // 空間O(n)// 優化建議
List<Product> productList = new ArrayList<>(); // 動態空間管理

六、代碼缺陷與改進

現存問題

  1. 數組越界風險
// 當i超過N時訪問products[i]會導致異常
while(W >= products[i].w) // 需添加i <= N條件判斷
  1. 精度丟失問題
// double計算存在精度誤差
new DecimalFormat("#.00").format(...) // 建議改用BigDecimal

改進方案

// 優化后的排序實現(使用Java內置排序)
Arrays.sort(products, 1, N+1, (a,b) -> Double.compare(b.wm, a.wm));// 優化后的容量檢查
while(i <= N && W >= products[i].w) {// ...原有邏輯
}

七、應用場景擴展

實際應用案例

  1. 貨物裝載優化:海運集裝箱的貨物配載
  2. 資源分配:云計算中的資源分配策略
  3. 投資組合:金融資產的部分投資

性能測試數據

物品規模冒泡排序耗時快速排序耗時
1002ms0.3ms
1000150ms1.2ms
1000015s5ms

八、算法擴展思考

動態規劃對比

特性貪心算法動態規劃
時間復雜度O(n2)O(nW)
空間復雜度O(n)O(nW)
解的質量最優最優
適用場景可分割物品不可分割

多約束擴展

當存在多維約束(體積+重量)時,可引入:

max Σ(v_i*x_i) 
s.t.
Σ(w_i*x_i) ≤ W 
Σ(v_i*x_i) ≤ V 
0 ≤ x_i ≤ 1

九、總結與展望

本實現完整展示了貪心算法在部分背包問題中的應用,核心在于:

  1. 正確計算單位價值
  2. 有效排序策略
  3. 分階段裝入邏輯

雖然當前實現存在時間復雜度較高的瓶頸,但通過:

  • 改進排序算法
  • 增加邊界檢查
  • 提升計算精度
    可將其升級為生產級解決方案。該算法在物流優化、金融投資等領域具有重要實踐價值。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/76662.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76662.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/76662.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

13. Langchain異步處理:提升應用性能的關鍵技巧

引言&#xff1a;從"順序等待"到"并行加速" 2025年某電商平臺引入LangChain異步處理后&#xff0c;大促期間訂單處理能力提升5倍&#xff0c;系統響應延遲降低70%。本文將基于LangChain的異步架構&#xff0c;詳解如何通過并行執行流式處理&#xff0c;讓…

ros2-rviz2控制unity仿真的6關節機械臂,探索從仿真到實際應用的過程

文章目錄 前言&#xff08;Introduction&#xff09;搭建開發環境&#xff08;Setup Development Environment&#xff09;在window中安裝Unity&#xff08;Install Unity in window&#xff09;創建Docker容器&#xff0c;并安裝相關軟件&#xff08;Create Docker containers…

計算機組成原理筆記(十四)——3.4指令類型

一臺計算機的指令系統可以有上百條指令&#xff0c;這些指令按其功能可以分成幾種類型&#xff0c;下面分別介紹。 3.4.1數據傳送類指令 一、核心概念與功能定位 數據傳送類指令是計算機指令系統中最基礎的指令類型&#xff0c;負責在 寄存器、主存、I/O設備 之間高效復制數…

各開源協議一覽

在 GitHub 上&#xff0c;開源項目通常會使用一些常見的開源協議來定義項目的使用、修改和分發規則。以下是目前 GitHub 上最常見的幾種開源協議及其差異和示例說明&#xff1a; TL;DR 協議寬松程度是否強制開源專利保護適用場景MIT最寬松否無希望代碼被廣泛使用Apache 2.0寬松…

51c自動駕駛~合集17

我自己的原文哦~ https://blog.51cto.com/whaosoft/13793157 #匯聚感知、定位、規劃控制的自動駕駛系統 自動駕駛技術在應用到車輛上之后可以通過提高吞吐量來緩解道路擁堵&#xff0c;通過消除人為錯誤來提高道路安全性&#xff0c;并減輕駕駛員的駕駛負擔&#xff0c;從…

小程序開發指南

小程序開發指南 目錄 1. 小程序開發概述 1.1 什么是小程序1.2 小程序的優勢1.3 小程序的發展歷程 2. 開發準備工作 2.1 選擇開發平臺2.2 開發環境搭建2.3 開發模式選擇 3. 小程序開發流程 3.1 項目規劃3.2 界面設計3.3 代碼開發3.4 基本開發示例3.5 數據存儲3.6 網絡請求3.7 …

Day15:關于MySQL的編程技術——基礎知識

前言&#xff1a;先創建一個練習的數據庫和數據 1.創建數據庫并創建數據表的基本結構 -- 創建練習數據庫 CREATE DATABASE db_programming; USE db_programming;-- 創建員工表&#xff08;包含各種數據類型&#xff09; CREATE TABLE employees (emp_id INT PRIMARY KEY AUTO…

批處理腳本bat丨遍歷一個包含項目名稱的數組,并對每個文件中的項目執行 git pull 操作 (一鍵拉很多文件的代碼)

文章目錄 前言一、操作方式二、文件展示三、分析代碼結構四、代碼五、需要注意的潛在問題六、改進后的代碼七、改進說明八、感謝 前言 由于之前git服務部署在本地服務器&#xff0c;處于代碼安全角度考慮。領導讓我將所有的項目代碼手動物理備份一份并且發給他。 這種傻傻的操…

【C++】C與C++、C++內存空間、堆與棧

C嘎嘎嘎嘎嘎~ C與C的區別與聯系 C內存空間 int global_var; // 未初始化全局變量&#xff0c;BSS段 const char* str "Hello"; // 字符串常量text段 in數據段void func() {static int static_var; // 未初始化的靜態變量&#xff0c;數據段int local_var; …

舵機:機器人領域的“關節革命者”

機器人的技術&#xff0c;每一個細微的進步都可能引領一場行業變革。而在這場變革中&#xff0c;舵機作為機器人關節的核心部件&#xff0c;正悄然上演著一場革命性的應用風暴。從簡單的關節運動到復雜的姿態控制&#xff0c;舵機以其卓越的性能和無限的可能&#xff0c;重新定…

微前端的不斷探索之路—— qiankun 實戰與思考!

全文目錄&#xff1a; 開篇語&#x1f4dd; 前言&#x1f6e0;? 微前端是什么&#xff1f;為什么需要它&#xff1f;&#x1f4a1; 先從“前端痛點”說起&#x1f9d0; 微前端的優勢 &#x1f939;?♀? qiankun 簡介與核心概念&#x1f31f; 為什么選擇 qiankun&#xff1f;…

拆解加密黑盒

在Web安全與數據爬取領域&#xff0c;JavaScript加密黑盒的逆向工程是核心技術之一。本文基于行業通用方法論與實戰案例&#xff0c;提煉出一套標準化的五步逆向流程&#xff0c;涵蓋目標定位、代碼提取、邏輯分析、算法復現到自動化集成的全鏈路解決方案&#xff0c;幫助開發者…

IntelliJ IDEA 中安裝和使用通義靈碼 AI 編程助手教程

隨著人工智能技術的發展&#xff0c;AI 編程助手逐漸成為提升開發效率的強大工具。通義靈碼是阿里云推出的一款 AI 編程助手&#xff0c;它能夠幫助開發者實現智能代碼補全、代碼解釋、生成單元測試等功能&#xff0c;極大地提升了編程效率和代碼質量。 IntelliJ IDEA 是一款廣…

Redis 特性和應用場景

1. Redis特性 1&#xff09;In-memory data structures Redis 在內存中存儲數據&#xff0c;key 是 String&#xff0c; value 可以是 hash, list, set, sorted set, stream ... MySQL主要是通過 “表” 的方式來存儲組織數據的 “關系型數據庫” Redis主要是通過 “鍵值對”…

每天五分鐘深度學習:非線性激活函數的導數

本文重點 本文探討了神經網絡中幾種常見非線性激活函數(Sigmoid、Tanh、ReLU、Leaky ReLU、ELU、Softmax)的導數特性。通過對各激活函數導數的數學推導與實際應用分析,揭示了不同激活函數在梯度傳播、收斂速度及模型表達能力方面的差異。研究發現,ReLU及其變體在計算效率與…

redis哨兵機制 和集群有什么區別:

主從&#xff1a; 包括一個master節點 和多個slave節點&#xff1a; master節點負責數據的讀寫&#xff0c;slave節點負責數據的讀取&#xff0c;master節點收到數據變更&#xff0c;會同步到slave節點 去實現數據的同步。通過這樣一個架構可以去實現redis的一個讀寫分離。提升…

關于讀完《毛澤東選集》的一些思考迭代

看完毛選前四卷&#xff0c;從革命初期一直講到抗戰勝利&#xff0c;共75.8W字&#xff0c;花費67個小時讀完。從1925年發表的“中國社會各階級的分析”&#xff0c;跨越100年&#xff0c;通過67個小時向主席學習到&#xff1a; 實事求是 從實踐中來再到實踐中去 用辯證與發展…

MySQL——MVCC(多版本并發控制)

目錄 1.MVCC多版本并發控制的一些基本概念 MVCC實現原理 記錄中的隱藏字段 undo log undo log 版本鏈 ReadView 數據訪問規則 具體實現邏輯 總結 1.MVCC多版本并發控制的一些基本概念 當前讀&#xff1a;該取的是記錄的最新版本&#xff0c;讀取時還要保證其他并發事務…

【Linux篇】深入理解文件系統:從基礎概念到 ext2 文件系統的應用與解析

文件系統的魔法&#xff1a;讓計算機理解并存儲你的數據 一. 文件系統1.1 塊1.2 分區1.3 inode(索引節點) 二. ext2文件系統2.1 認識文件系統2.2 Block Group (塊組)2.2.1 Block Group 的基本概念2.2.2 Block Group 的作用 2.3 塊組內部結構2.3.1 超級塊&#xff08;Super Bloc…

3 VS Code 配置優化與實用插件推薦:settings.json 詳解、CodeGeeX 智能編程助手及插件離線安裝方法

1 優化 settings.json 文件 1.1 settings.json 簡介 settings.json 是 VS Code 的核心配置文件&#xff0c;用于存儲用戶的個性化設置和偏好。通過該文件&#xff0c;用戶可以自定義和覆蓋 VS Code 的默認行為&#xff0c;包括但不限于以下方面&#xff1a; 編輯器外觀&#…