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

HDU 4952 Poor Mitsui:貪心相鄰交換法證明最優處理順序

     編輯:C++ 入門

問題描述

有 n 項任務,每項有 a_i (處理時間) 和 b_i (懲罰係數)。初始容量 V。處理任務 i 時,若當前容量 v ≤ a_i 則失敗。否則容量變為 v - a_i,總懲罰增加 b_i / (v - a_i)。求任務順序使總懲罰最小。n ≤ 40。

貪心策略:相鄰交換法證明

考慮相鄰任務 i, j。設處理 i 前容量為 v。
順序 i→j 懲罰:b_i/(v-a_i) + b_j/(v-a_i-a_j)
順序 j→i 懲罰:b_j/(v-a_j) + b_i/(v-a_j-a_i)
比較兩者,經代數變形得:
i→j 優於 j→i ⇔ b_i/a_i < b_j/a_j ⇔ b_i·a_j < b_j·a_i

故按 b/a 升序排序(即 b_i·a_j < b_j·a_i)即為最優序。這是經典的「相鄰交換法」證明貪心最優性。

特殊情況處理

  • b_i = 0:懲罰為 0,放在最前(不影響後續容量)
  • 若存在 a_i ≥ V:無論順序如何,處理該任務時容量必 ≤ a_i,無解 → 輸出 -1

C++ 實現

#include 
#include 
using namespace std;
struct Task { int a, b; } t[45];

bool cmp(Task x, Task y) {
    return 1LL * x.b * y.a < 1LL * y.b * x.a; // b/a 升序
}

double solve(Task t[], int n, int V) {
    for (int i=0; i= V) return -1; // 必須 b>0 才構成威脅
    double ans = 0, v = V;
    for (int i=0; i

關鍵細節

  • 比較函數用長整型:1LL * x.b * y.a 防溢出
  • b=0 任務:不產生懲罰,可放最前;但會消耗容量?代碼中 continue 跳過懲罰計算但未扣容量,需確認題意。通常 b=0 仍消耗 a,只不計懲罰
  • 輸出格式:%.0f 四捨五入整數

相鄰交換法通用模板

  1. 假設最優序中存在相鄰逆序對
  2. 交換它們,計算目標函數變化 Δ
  3. 證明 Δ ≥ 0(或 ≤ 0),說明交換不劣(或更優)
  4. 結論:無逆序對的序列(即按關鍵字排序)為最優

此題是「相鄰交換法證明貪心序」的教科書級範例,將複雜的序列優化問題化為簡單的排序規則。

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