傳送門
乙個餐廳在相繼的 \(n\) 天裡,每天需用的餐巾數不盡相同。假設第 \(i\) 天需要 \(r_i\) 塊餐巾(\(i=1,2,...,n\))。餐廳可以購買新的餐巾,每塊餐巾的費用為 \(p\) 分;或者把舊餐巾送到快洗部,洗一塊需 \(m\) 天,其費用為 \(f\) 分;或者送到慢洗部,洗一塊需 \(n\) 天(\(n>m\)),其費用為 \(s\) 分(\(s)。
每天結束時,餐廳必須決定將多少塊髒的餐巾送到快洗部,多少塊餐巾送到慢洗部,以及多少塊儲存起來延期送洗。但是每天洗好的餐巾和購買的新餐巾數之和,要滿足當天的需求量。
試設計乙個演算法為餐廳合理地安排好 \(n\) 天中餐巾使用計畫,使總的花費最小。程式設計找出乙個最佳餐巾使用計畫。
第 1 行有 1 個正整數 \(n\),代表要安排餐巾使用計畫的天數。
接下來的一行是餐廳在相繼的 \(n\) 天裡,每天需用的餐巾數。
最後一行包含5個正整數\(p,m,f,n,s\)。\(p\) 是每塊新餐巾的費用; \(m\) 是快洗部洗一塊餐巾需用天數; \(f\) 是快洗部洗一塊餐巾需要的費用; \(n\) 是慢洗部洗一塊餐巾需用天數; \(s\) 是慢洗部洗一塊餐巾需要的費用。
將餐廳在相繼的 \(n\) 天裡使用餐巾的最小總花費輸出。
不難看出,這是一道最小費用流的題目。此類問題建模時,一定要注意「最小費用基於最大流」,要使問題的最終答案在網路中一定對應乙個最大流才行。否則辛苦打**,等到輸出時才發現建模錯誤,那會浪費不少時間。(親身經歷)
首先,將每天看做乙個點,那麼流入這個點的流量不能小於\(r\)。題面中的「每天結束時」也啟發我們用點邊轉化的方式,即拆點,處理此題。
不難想到乙個看似正確的做法:將每個點拆成「早上的點」與「晚上的點」,並從早點向晚點連\((r,0)\)(容量為r,費用為0)的邊。設乙個虛擬源點\(s\),從\(s\)向所有早點連\((+∞,p)\)的邊,表示每天早上可以買任意條餐巾。設虛擬匯點\(t\)(垃圾桶),從所有晚點向\(t\)連\((+∞,0)\)的邊,表示髒餐巾可以任意丟棄。在從每個第\(x\)天的晚點向第\(x+m\)天的早點連\((r_x,f)\)的邊,表示快洗,慢洗同理;另外,每天早上的餐巾可以留到下一天,從\(x\)天的早點向\(x+1\)天的早點連\((+∞,0)\)的邊。
然後在這張網路上跑費用流模板。樣例炸了。此時模擬樣例就會發現:這種網路可以保證答案對應的可行流\(f\)每天的流量一定等於r,但不保證在流入匯點時\(f\)仍為最大流!換言之,雖然可以建立原問題與可行流的對應關係,但原問題的解不是最大流,也自然不能用費用流的方式求解。只能重新建模。
\(f\)在此網路上不是最大流,原因在於晚點連向匯點的邊。因為有「洗餐巾」的條件,我們連線了晚點\(x\)與其他早點的邊。但這會導致\(x\)向匯點的流量減少,自然無法成為最大流。於是考慮刪去晚點向匯點的邊,並用其他等效條件替代。
注意到所有晚點均僅由其對應的早點提供流量,而匯點的流量僅由所有晚點提供。那麼不如斷開晚點向匯點的邊,改連早點向匯點連\((r,0)\)的邊。與此對應,需從源點向匯點連\((r,0)\)的邊。我們再考慮新網路能否與原問題建立一一對應關係。此時早點向匯點的邊含義變為:第\(x\)天的所有乾淨餐巾為\(r\)條,不管之後的去向如何,但最終一定歸於垃圾桶;源點向晚點的邊含義為:第\(x\)天產生\(r\)條髒餐巾。這樣的建模非常巧妙,實現了對應,且原問題的對應可行流一定是最大流。
#include#include#include#define ll long long
using namespace std;
const int n = 4000 + 5;
const int m = 2e5 + 5;
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3fll;
int n, s, t, r[n], p, t1, v1, t2, v2;
int head[n], nxt[m], ver[m], c[m], tot = 1;
int incf[n], pre[n], v[n];
ll w[m], dis[n];
void add(int x, int y, int cap, int val)
bool spfa() }}
}return dis[t] != linf;
}int main()
ll cost = 0;
while (spfa())
}printf("%lld\n", cost);
return 0;
}
學到乙個小技巧:memset對long long使用時,0x3f表示0x3f3f3f3f3f3f3f3f
,其兩倍接近\(2^-1\),相似於0x3f3f3f3f
在int中的地位。
網路流問題注重建模。訓練的方式為刷題+理解歸納。
洛谷 P1251 餐巾計畫問題
吃什麼 先說建圖 經典構圖題。將每一天拆成兩個點i,i 加如下6條邊 s i,r i,p 在第 i 天可以買至多ri 個餐巾,每塊 p 分 i t,r i,0 第i 天要用ri 塊餐巾 s i ri,0 第 i 天用剩的ri 塊舊餐巾 i i m,f 第 i 天的舊餐巾送到快洗部,每塊 f分 i i...
P1251 餐巾計畫問題
題面 一道特別棒的費用流好題,思路非常巧妙 對於每一天,我們分為早上和晚上兩個節點 每天早上會消耗 r i 條乾淨的毛巾,可以視為流向匯點,所以我們向匯點連一條流量為 r i 費用為 0 的邊 每天晚上會產生 r i 條髒毛巾,可以視為從源點流出,所以我們從源點連一條流量為 r i 費用為 0 的邊...
P1251 餐巾計畫問題
因為髒的衣服在一天結束時才會有,乾淨的一天開始才會有,考慮拆點。再考慮乾淨的衣服都是要被收集起來的,所以乾淨的要流向超匯。而髒的衣服可以從超源免費獲得所需要的個數,而乾淨的衣服只能購買。看張圖吧,假如只有 1 個點的話,且需要無限多的衣服。顯然前者正確,後者矛盾 收集了髒衣服 再者,這種建圖會無法收...