引用《24題》:
把每天分為二分圖兩個集合中的頂點xi,yi,建立附加源s匯t。
1、從s向每個xi連一條容量為ri,費用為0的有向邊。
2、從每個yi向t連一條容量為ri,費用為0的有向邊。
3、從s向每個yi連一條容量為無窮大,費用為p的有向邊。
4、從每個xi向xi+1(i+1<=n)連一條容量為無窮大,費用為0的有向邊。
5、從每個xi向yi+m(i+m<=n)連一條容量為無窮大,費用為f的有向邊。
6、從每個xi向yi+n(i+n<=n)連一條容量為無窮大,費用為s的有向邊。
求網路最小費用最大流,費用流值就是要求的最小總花費。
【建模分析】
這個問題的主要約束條件是每天的餐巾夠用,而餐巾的**可能是最新購買,也可能是前幾天送洗,今天剛剛洗好的餐巾。每天用完的餐巾可以選擇送到快洗部或慢洗部,或者留到下一天再處理。
經過分析可以把每天要用的和用完的分離開處理,建模後就是二分圖。二分圖x集合中頂點xi表示第i天用完的餐巾,其數量為ri,所以從s向xi連線容量為ri的邊作為限制。y集合中每個點yi則是第i天需要的餐巾,數量為ri,與t連線的邊容量作為限制。每天用完的餐巾可以選擇留到下一天(xi->xi+1),不需要花費,送到快洗部(xi->yi+m),費用為f,送到慢洗部(xi->yi+n),費用為s。每天需要的餐巾除了剛剛洗好的餐巾,還可能是新購買的(s->yi),費用為p。
在網路上求出的最小費用最大流,滿足了問題的約束條件(因為在這個圖上最大流一定可以使與t連線的邊全部滿流,其他邊只要有可行流就滿足條件),而且還可以保證總費用最小,就是我們的優化目標。
總時間耗費: 2598ms
總記憶體耗費: 876b
#include#include#include#include#includeusing namespace std;
const int maxn = 5000 + 10;
const int inf = 1e9 + 7;
struct edge ;
int n, s, t;
vectorg[maxn];
vectoredges;
void addedge(int from, int to, int cap, int cost) );
edges.push_back((edge));
int m = edges.size();
g[from].push_back(m-2);
g[to].push_back(m-1);
}int d[maxn], p[maxn], a[maxn];
bool inq[maxn];
bool bellmanford(int& cost)
}} }
if(d[t] == inf) return 0;
cost += d[t]*a[t];
int x = t;
while(x != s)
return 1;
}int mincostmaxflow()
int main()
cout << mincostmaxflow() << endl;
return 0;
}
P1251 餐巾計畫問題
題面 一道特別棒的費用流好題,思路非常巧妙 對於每一天,我們分為早上和晚上兩個節點 每天早上會消耗 r i 條乾淨的毛巾,可以視為流向匯點,所以我們向匯點連一條流量為 r i 費用為 0 的邊 每天晚上會產生 r i 條髒毛巾,可以視為從源點流出,所以我們從源點連一條流量為 r i 費用為 0 的邊...
洛谷 1251 餐巾計畫問題
題鏈 題解 一點啟示 建圖時要考慮到流量問題,即為了方便使用最小費用最大流演算法,要把流量最大時為最終目的考慮進建圖。拆點,每天拆為兩個點i,i 表示每天開始和每天結束 s,i,ai,p 在第i天最多買ri個餐巾,花費為p i,t,ai,0 第i天要用ai塊餐巾 s,i ai,0 第i天用剩的ai塊...
Luogu P1251 餐巾計畫問題
不得不說這是一道非常好的費用流神題。建圖清新自然,構建沒有毒瘤。實為網路流24題中難得一見的好題。我們考慮一下網路流的建圖。首先拆點並建立超級源點ss和超級匯點 t 常見套路 我們把每一天拆成早上 x i 和晚上 y i 然後考慮每天早上要向 t 提供 r i 條乾淨的餐巾,而 s 要向每天晚上提供...