貪心算法應用:航班起降問題詳解

在這里插入圖片描述

Java中的貪心算法應用:航班起降問題詳解

貪心算法是一種在每一步選擇中都采取當前狀態下最優的選擇,從而希望導致全局最優解的算法策略。在航班起降問題中,貪心算法可以有效地解決機場跑道調度問題,即如何安排航班的起降順序以最大化利用跑道資源。

一、問題描述

航班起降問題(也稱為區間調度問題)可以描述為:

給定一組航班的起降時間區間,每個區間表示為[start_i, end_i],其中start_i是航班i的起飛時間,end_i是航班i的降落時間。由于跑道資源有限,我們需要安排一個調度方案,使得在任意時刻跑道上最多只有一個航班在起降。我們的目標是安排盡可能多的航班使用跑道。

二、問題分析

這個問題可以轉化為經典的區間調度問題,即在多個重疊的區間中選擇盡可能多的互不重疊的區間。貪心算法是解決這類問題的有效方法。

關鍵點:

  1. 沖突定義:兩個航班區間[s1, e1][s2, e2]沖突當且僅當它們有重疊,即s1 < e2s2 < e1
  2. 目標:選擇最大數量的互不沖突的航班區間。
  3. 貪心策略:有多種貪心選擇策略可以考慮:
    • 最早開始時間
    • 最短持續時間
    • 最早結束時間

實踐證明,選擇最早結束時間的策略可以得到最優解。

三、貪心算法解決方案

算法步驟:

  1. 將所有航班按照結束時間從小到大排序
  2. 初始化已選航班集合為空,記錄最后一個選中航班的結束時間
  3. 遍歷排序后的航班列表:
    • 如果當前航班的開始時間不早于最后一個選中航班的結束時間
    • 則選擇該航班,并更新最后一個選中航班的結束時間
  4. 返回已選航班集合

Java實現代碼:

import java.util.Arrays;
import java.util.Comparator;public class FlightScheduling {static class Flight {int start;int end;public Flight(int start, int end) {this.start = start;this.end = end;}@Overridepublic String toString() {return "[" + start + ", " + end + "]";}}public static int maxFlights(Flight[] flights) {// 邊界條件檢查if (flights == null || flights.length == 0) {return 0;}// 按照航班結束時間升序排序Arrays.sort(flights, new Comparator<Flight>() {@Overridepublic int compare(Flight a, Flight b) {return a.end - b.end;}});int count = 1; // 至少可以安排第一個航班int lastEnd = flights[0].end;for (int i = 1; i < flights.length; i++) {if (flights[i].start >= lastEnd) {// 當前航班可以安排,不沖突count++;lastEnd = flights[i].end;}}return count;}public static Flight[] scheduleFlights(Flight[] flights) {if (flights == null || flights.length == 0) {return new Flight[0];}// 按照航班結束時間升序排序Arrays.sort(flights, new Comparator<Flight>() {@Overridepublic int compare(Flight a, Flight b) {return a.end - b.end;}});// 使用列表動態存儲結果java.util.ArrayList<Flight> result = new java.util.ArrayList<>();result.add(flights[0]);int lastEnd = flights[0].end;for (int i = 1; i < flights.length; i++) {if (flights[i].start >= lastEnd) {result.add(flights[i]);lastEnd = flights[i].end;}}return result.toArray(new Flight[0]);}public static void main(String[] args) {Flight[] flights = {new Flight(1, 4),new Flight(3, 5),new Flight(0, 6),new Flight(5, 7),new Flight(3, 8),new Flight(5, 9),new Flight(6, 10),new Flight(8, 11),new Flight(8, 12),new Flight(2, 13),new Flight(12, 14)};System.out.println("最大可安排航班數量: " + maxFlights(flights));Flight[] scheduled = scheduleFlights(flights);System.out.println("具體安排的航班:");for (Flight f : scheduled) {System.out.println(f);}}
}

代碼解析:

  1. Flight類:表示航班,包含開始時間和結束時間。
  2. maxFlights方法:計算可以安排的最大航班數量。
  3. scheduleFlights方法:返回具體的航班安排方案。
  4. 排序:按照航班結束時間升序排序,這是貪心算法的關鍵。
  5. 選擇策略:每次選擇結束時間最早且不與已選航班沖突的航班。

四、算法正確性證明

為了證明這個貪心算法的正確性,我們需要證明選擇最早結束的航班可以得到最優解。

證明:

  1. 設貪心算法選擇的航班序列為G = {g?, g?, …, g?}。
  2. 設最優解為O = {o?, o?, …, o?},且O是按結束時間排序的。
  3. 我們需要證明m = n。

歸納法證明:

  • 對于k=1:貪心算法選擇最早結束的航班g?,因為任何包含比g?結束更晚的航班o?的解,都可以用g?替換o?而不減少航班數量。
  • 假設對于前k個選擇,貪心算法與某個最優解一致。
  • 對于第k+1個選擇,貪心算法選擇在g?結束后最早結束的航班g???。任何最優解中第k+1個航班o???的結束時間不會早于g???,因此可以用g???替換o???。

因此,貪心算法得到的解與最優解航班數量相同。

五、復雜度分析

  1. 時間復雜度

    • 排序:O(n log n),使用快速排序或歸并排序。
    • 遍歷:O(n)。
    • 總時間復雜度:O(n log n)。
  2. 空間復雜度

    • 排序:O(log n)的棧空間(對于快速排序)。
    • 存儲結果:O(n)(如果需要存儲具體安排)。
    • 如果只計算數量,空間復雜度為O(1)。

六、變種問題及解決方案

1. 最少跑道問題

問題:給定航班起降時間,計算至少需要多少條跑道才能滿足所有航班需求。

解決方案

  • 這可以轉化為計算最大重疊航班數的問題。
  • 將所有開始和結束時間點排序,掃描時間線統計最大重疊數。
public static int minRunways(Flight[] flights) {int n = flights.length;int[] starts = new int[n];int[] ends = new int[n];for (int i = 0; i < n; i++) {starts[i] = flights[i].start;ends[i] = flights[i].end;}Arrays.sort(starts);Arrays.sort(ends);int runways = 0;int maxRunways = 0;int i = 0, j = 0;while (i < n && j < n) {if (starts[i] < ends[j]) {runways++;maxRunways = Math.max(maxRunways, runways);i++;} else {runways--;j++;}}return maxRunways;
}

2. 加權區間調度

問題:每個航班有不同的優先級或權重,目標是選擇一組互不沖突的航班使得總權重最大。

解決方案

  • 這無法用貪心算法解決,需要使用動態規劃。
  • 仍然按結束時間排序,對每個航班i,找到最后一個不與i沖突的航班j,然后比較包含i和不包含i的情況。
public static int maxWeightSchedule(Flight[] flights, int[] weights) {int n = flights.length;Arrays.sort(flights, Comparator.comparingInt(a -> a.end));// 預處理:對于每個i,找到p[i] = 最后一個不與i沖突的航班int[] p = new int[n];for (int i = 0; i < n; i++) {p[i] = -1;for (int j = i - 1; j >= 0; j--) {if (flights[j].end <= flights[i].start) {p[i] = j;break;}}}int[] dp = new int[n + 1];dp[0] = 0;for (int i = 1; i <= n; i++) {int include = weights[i - 1] + (p[i - 1] != -1 ? dp[p[i - 1] + 1] : 0);int exclude = dp[i - 1];dp[i] = Math.max(include, exclude);}return dp[n];
}

七、實際應用中的考慮因素

在實際的航班調度系統中,還需要考慮以下因素:

  1. 航班優先級:緊急航班、VIP航班等可能需要優先安排。
  2. 緩沖時間:航班之間需要留出安全間隔時間。
  3. 多跑道協調:大型機場有多條跑道,需要考慮協同調度。
  4. 航班延誤概率:考慮歷史延誤數據,提高調度魯棒性。
  5. 連接航班:確保轉機航班有足夠的時間間隔。

八、測試用例設計

為了驗證算法的正確性,需要設計全面的測試用例:

public static void testCases() {// 測試用例1:無航班Flight[] empty = {};assert maxFlights(empty) == 0;// 測試用例2:單個航班Flight[] single = {new Flight(1, 2)};assert maxFlights(single) == 1;// 測試用例3:無沖突的多個航班Flight[] noConflict = {new Flight(1, 2),new Flight(3, 4),new Flight(5, 6)};assert maxFlights(noConflict) == 3;// 測試用例4:完全沖突的航班Flight[] allConflict = {new Flight(1, 5),new Flight(2, 5),new Flight(3, 5)};assert maxFlights(allConflict) == 1;// 測試用例5:混合情況Flight[] mixed = {new Flight(1, 3),new Flight(2, 4),new Flight(3, 5),new Flight(4, 6)};assert maxFlights(mixed) == 2;// 測試用例6:邊界情況,航班剛好不沖突Flight[] edge = {new Flight(1, 2),new Flight(2, 3),new Flight(3, 4)};assert maxFlights(edge) == 3;System.out.println("所有測試用例通過!");
}

九、性能優化技巧

  1. 預處理p數組的優化
    在加權區間調度中,可以使用二分查找來優化p數組的計算:

    for (int i = 0; i < n; i++) {int low = 0, high = i - 1;p[i] = -1;while (low <= high) {int mid = (low + high) / 2;if (flights[mid].end <= flights[i].start) {p[i] = mid;low = mid + 1;} else {high = mid - 1;}}
    }
    

    這樣可以將預處理時間復雜度從O(n2)降低到O(n log n)。

  2. 并行處理
    對于大規模航班數據,可以將排序和掃描過程并行化處理。

  3. 內存優化
    如果只需要計算數量而不需要具體安排,可以避免存儲整個結果數組。

十、與其他算法的比較

  1. 動態規劃

    • 可以解決更一般的加權區間調度問題。
    • 時間復雜度通常更高(O(n2)或O(n log n))。
    • 適用于需要精確最優解的場景。
  2. 回溯法

    • 可以找到所有可能的調度方案。
    • 時間復雜度極高(O(2?))。
    • 僅適用于極小規模問題。
  3. 貪心算法

    • 簡單高效,時間復雜度低(O(n log n))。
    • 只能解決特定類型的優化問題。
    • 適用于需要快速近似解的大規模問題。

十一、實際工程實現建議

在實際工程中實現航班調度系統時,建議:

  1. 模塊化設計

    • 將航班數據加載、預處理、算法核心、結果輸出分離。
    • 便于維護和擴展。
  2. 異常處理

    • 處理無效的航班數據(如結束時間早于開始時間)。
    • 處理大規模數據時的內存溢出問題。
  3. 日志記錄

    • 記錄算法執行的關鍵步驟和時間。
    • 便于調試和性能分析。
  4. 配置化

    • 使排序策略、緩沖時間等參數可配置。
    • 適應不同的業務場景。
  5. 可視化

    • 提供航班調度結果的圖形化展示。
    • 便于人工驗證和調整。

十二、擴展

  1. 更復雜的調度模型

    • 考慮航班類型(起飛/降落)的不同資源需求。
    • 考慮多跑道之間的依賴關系。
  2. 實時調度系統

    • 處理動態到達的航班請求。
    • 考慮航班延誤的實時調整。
  3. 機器學習應用

    • 預測航班延誤概率。
    • 基于歷史數據優化調度策略。
  4. 分布式調度

    • 多機場協同調度。
    • 大規模航班數據的分布式處理。

總結

貪心算法在航班起降問題中提供了一種高效簡潔的解決方案,通過選擇最早結束的航班策略,可以在O(n log n)時間內找到最優解。雖然貪心算法不能解決所有變種問題,但對于基礎的區間調度問題,它是最佳選擇。理解這一算法的原理和實現細節,不僅有助于解決航班調度問題,也為處理其他類似的區間選擇問題提供了思路框架。

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

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

相關文章

uniapp scroll-view 設置scrollTop無效

當我們使用 scroll-view的scroll-top的時候 默認想讓它回到頂部&#xff0c;當我們設置值為0的時候會不生效&#xff0c;在實際運用過程中&#xff0c;發現設置了scroll-top無效&#xff0c;滾動條位置并沒有發生變化&#xff0c;是因為微信小程序的官方框架處于性能考慮&#…

網絡與通信

1.TCP協議與UDP協議TCP&#xff08;Transmission Control Protocol&#xff0c;傳輸控制協議&#xff09;和 UDP&#xff08;User Datagram Protocol&#xff0c;用戶數據報協議&#xff09;是 TCP/IP 協議族中兩種核心的傳輸層協議&#xff0c;它們在數據傳輸方式、可靠性、適…

Node.js中package.json詳解

1. name&#xff08;名稱&#xff09; 如果你計劃發布你的包&#xff0c;package.json 中最重要的字段是 name 和 version&#xff0c;因為它們是必需的。name 和 version 共同組成一個假定完全唯一的標識符。包的更改應伴隨版本號的更新。如果你不打算發布包&#xff0c;那么…

代碼隨想錄第14天| 翻轉、對稱與深度

226.翻轉二叉樹 &#xff08;優先掌握遞歸&#xff09; 題目鏈接/文章講解/視頻講解&#xff1a;翻轉二叉樹 交換的是指針&#xff0c;而不是數值&#xff0c;如果用數值做交換&#xff0c;需要交換的節點下面無法很好的操作。 使用遞歸來實現&#xff0c;但要提前清除是什么順…

DNS-Windows上使用DNS

DNS-Windows上使用DNS一、查看與修改DNS配置1.1、查看當前DNS服務器設置1.2、臨時修改 DNS 服務器&#xff08;命令行&#xff09;二、DNS緩存相關操作2.1、查看DNS緩存內容2.2、 刷新 DNS 緩存&#xff08;清除過期記錄&#xff09;三、測試域名解析&#xff08;nslookup 工具…

3dsMax 2026 .NET Core 8 轉型下的Maxscript腳本開發:動態編譯模塊的重構策略與兼容性升級路徑

3ds Max 長期以來一直提供出色的 .NET 集成,使 Maxscript 能夠無縫利用任何 .NET 庫的強大功能。部分開發者在工具中廣泛使用了 .NET 功能。 之前,3ds Max 依賴于 .NET Framework 4.8 并且最近更新到了 4.8.1,用于 2025 版本的發布。然而,隨著 3ds Max 2026 的推出,Autod…

golang 做webrtc開發核心

在Golang中進行WebRTC開發&#xff0c;核心在于理解WebRTC協議的工作原理以及如何利用Go生態中的庫來實現關鍵功能。以下是Golang WebRTC開發的核心要點&#xff1a; WebRTC基礎概念 了解ICE&#xff08;Interactive Connectivity Establishment&#xff09;協議用于NAT穿越掌握…

RabbitMQ 異步化抗洪實戰

說明&#xff1a;本文僅展示架構思路與安全片段&#xff0c;所有敏感字段已用占位符&#xff1b;不含可直接復刻的生產細節。數據與接口均為演示/虛擬。0. 背景與目標長耗時/不確定接口&#xff08;如對接第三方機器人平臺&#xff09;的同步阻塞&#xff0c;容易造成請求堆積與…

接口返回 2 萬條數據,easy-trans導致多了20s耗時排查過程

內網訪問排版核料詳情功能&#xff0c;用戶反饋要等十幾秒排查 sql&#xff1a;sql 比較簡單排查內存計算&#xff1a;arthus trace 類名 方法名 總耗時2s排查頁面渲染是否緩慢&#xff1a;F12 查看接口 等待服務器響應 20s 下載時間 30s, 故不考慮渲染問題排查請求響應日志打…

AIGC入門,手搓大模型客戶端與MCP交互

概述 在現代應用開發中&#xff0c;將大語言模型&#xff08;LLM&#xff09;與專用工具服務相結合&#xff0c;可以構建出既能理解自然語言&#xff0c;又能準確執行專業任務的智能代理。本文介紹一個基于 MCP&#xff08;Model Context Protocol&#xff09;協議和 Ollama 本…

深度學習:從預備知識到未來展望

在當今數字化時代&#xff0c;深度學習正以前所未有的速度改變著我們的生活和工作方式。從智能語音助手到自動駕駛汽車&#xff0c;從精準醫療到個性化推薦系統&#xff0c;深度學習的應用無處不在。本文將從深度學習的預備知識入手&#xff0c;探討其發展歷程、關鍵技術和未來…

軟考高級系統架構設計師之構件與中間件技術篇

一、構件的定義 定義1:軟件構件是一種組裝單元&#xff0c;它具有規范的接口規約和顯式的語境依賴。軟件構件可以被獨立地部署并由第三方任意地組裝。 定義2:構件是某系統中有價值的、幾乎獨立的并可替換的一個部分&#xff0c;它在良好定義的體系結構語境內滿足某清晰的功能。…

Node.js 文件上傳中文文件名亂碼問題,為什么只有Node會有亂碼問題,其他后端框架少見?

問題現象當用戶上傳包含中文字符的文件時&#xff0c;在服務器端獲取到的文件名可能變成類似 ????.txt 這樣的亂碼&#xff0c;而不是預期的中文文件名。為什么只有Node會亂碼&#xff1f;很多后端框架&#xff08;如 Java Spring Boot、Python Django、PHP Laravel&#x…

學習英語音標 (從漢語角度看英語音標發音差異)

僅供參考, 跟著教學視頻看不懂時再來看以下引導 以下只寫容易出錯的音標 發音視頻: https://www.jiwake.com/yinbiaofayin/ 音標規則單詞??類似漢語e, 餓~urge?類似漢語e, 餓go??類似漢語o, 哦~walk?類似漢語o, 哦wash?/i?/的短語, 不止發聲短,舌頭不用隆起it?類似漢…

論文筆記(九十一)GWM: Towards Scalable Gaussian World Models for Robotic Manipulation

GWM: Towards Scalable Gaussian World Models for Robotic Manipulation文章概括摘要1. 引言2. 相關工作3. 高斯世界模型&#xff08;Gaussian World Model&#xff09;3.1. 世界狀態編碼&#xff08;World State Encoding&#xff09;3.2. 基于擴散的動態建模&#xff08;Dif…

apache phoenix sql 命令大全詳解

這是一份非常詳細的 Apache Phoenix SQL 命令大全和詳解。Phoenix 作為 HBase 上的 SQL 層&#xff0c;其語法大部分與標準 SQL 兼容&#xff0c;但也有許多針對 HBase 的特性擴展。核心概念 在開始之前&#xff0c;請記住 Phoenix 的兩個核心概念&#xff1a; 主鍵&#xff08…

【代碼講解】SO-ARM100 雙場景演示:手柄驅動 Mujoco 仿真 + 實機控制

視頻講解&#xff1a; 【代碼講解】SO-ARM100 雙場景演示&#xff1a;手柄驅動 Mujoco 仿真 實機控制今天介紹下使用使用北通手柄通過控制 Mujoco 中的 SO-ARM100 機械臂&#xff0c;然后將關節數據通過 zmq 通信轉發控制實際機械臂。 本期中會涉及如下點&#xff0c;需要注意…

「數據獲取」《中國教育經費統計年鑒》(1997-2024)

01、數據簡介《中國教育經費統計年鑒》作為我國教育經費領域的核心統計典籍&#xff0c;全面系統地呈現了全國各級各類教育經費的來源構成、分配流向與使用成效。其統計范圍覆蓋學前教育、基礎教育、中等職業教育、高等教育及特殊教育等全學段&#xff0c;數據維度涵蓋財政性教…

使用 Logspout 收集所有容器的

1.將所有容器的輸出路由到遠程 rsyslog 服務器1.修改 rsyslog 配置文件/etc/rsyslog.conf, 從中找到 “# Provides UDP sysilog recepion"語句。并將該處的以下兩行配置代碼行首的“#”字符刪除&#xff08;取消注釋&#xff09;[roothost1 ~]# vi /etc/rsyslog.conf [roo…

【智能化解決方案】基于多目標優化檢索增強生成的智能行程規劃方案

&#x1f4dd; 基于多目標優化的智能行程規劃方案 1 用戶需求分析與矩陣構建 1.1 核心用戶信息提取 根據用戶提供的年齡、出發地、目的地、出行時間等基本信息&#xff0c;我們首先構建一個用戶特征向量&#xff1a; U {Age, Origin, Destination, TravelDate, Duration, Budg…