標籤:網路流
題目描述:
新的技術正衝擊著手機通訊市場,對於各大電訊廠商來說,這既是機遇,更是挑戰。THU 集團旗下的 CS&T 通訊公司在新一代通訊技術血戰的前夜,需要做太多的準備工作,僅就站址選擇一項,就需要完成前期市場研究、站址勘測、最佳化等項目。 在前期市場調查和站址勘測之後, 公司得到了一共 N個可以作為通訊訊號中轉站的地址,而由於這些地址的地理位置差異,在不同的地方建造通訊中轉站需要投入的成本也是不一樣的,所幸在前期調查之後這些都是已知資料:建立第 i個通訊中轉站需要的成本為Pi(1≤i≤N) 。 另外公司調查得出了所有期望中的使用者群,一共 M 個。關於第i個使用者群的資訊概括為Ai, Bi 和Ci:這些使用者會使用中轉站 Ai和中轉站 Bi進行通訊,公司可以獲益Ci。 (1≤i≤M, 1≤Ai, Bi≤N) THU 集團的CS&T公司可以有選擇的建立一些中轉站(投入成本) ,為一些使用者提供服務並獲得收益(獲益之和) 。那麼如何選擇最終建立的中轉站才能讓公司的淨獲利最大呢?(淨獲利 = 獲益之和 – 投入成本之和)
思路:經典的網路流模型,建立模型的時候可以參考二分圖模型的建立。把中轉站視作x部,使用者群視作y部,使用者群需要的中轉站之間連一條有向邊(使用者群向中轉站),容量為無窮大。虛擬一個源點,向x部每個點連一條有向邊,容量為中轉站的成本。再虛擬一個匯點,y部每個點向匯點連一條有向邊,權值為使用者群的獲利。求得該圖的最小割。用使用者群獲利的和減去最小割就是要求的最大獲利,為什麼呢?我們求得的最小割是沒有用到的使用者群的獲利加上用到的中轉站的成本(畫個圖理解理解吧),然後總利潤減去最小割就是最大獲利了。
#include<cstdio>#include<vector>#define MAXN 60005#define INF 999999999#define BIG 123456789#define Min(a,b) a<b?a:busing namespace std;struct T{int v;int w;int op;//儲存反向邊編號T(){}T(int a,int b,int c){v = a;w = b;op = c;}};vector<T> g[MAXN];//殘留網路int d[MAXN];//距離標號int vd[MAXN];//標號為i的節點個數int m,n,flow,sum,N;//N:頂點數,flow:最大流(本題實則是最小割),sum:所有利潤和int aug(int i,int augco)//頂點i,augco:從i為起點的最大增廣容量 {int j,augc = augco,mind = N-1,delta;if(i == N) return augco;//到達匯點for(j = 0; j < g[i].size(); j++)//枚舉i的鄰接點{int v = g[i][j].v;int w = g[i][j].w;if(w)//如果有邊到j,最先忘寫這句了,結果瘋狂TLE{if(d[i] == d[v]+1)//(i,j)為可進入弧{delta = Min(augc,w);//求出經(i,j)的可增廣最大值delta = aug(v,delta);//遞迴增廣,返回沿(i,j)的實際增廣量g[i][j].w -= delta;//更新殘留網路g[v][g[i][j].op].w += delta;augc -= delta; //augc記錄剩下的需要增廣的量if(d[1] >= N) return augco - augc;//結束,向上一層返回經過i的實際增廣量if(augc == 0) break; //已經到達可增廣上界,提前跳出}mind = Min(mind,d[v]);//更新最小的鄰接點標號}}if(augco == augc)//如果從i點無法增廣{vd[d[i]]--;//標號為d[i]的結點數-1if(vd[d[i]] == 0) d[1] = N;//GAP最佳化d[i] = mind+1; //更新標號vd[d[i]]++;//新標號的結點數+1}return augco - augc;//向上一層返回經過i的實際增廣量}void sap(){vd[0] = N;while(d[1] < N-1)flow += aug(1,BIG);}int main(){int a,b,c;scanf("%d%d",&n,&m);for(int i = 1; i <= n; i++){scanf("%d",&a);g[1].push_back(T(i+1,a,g[i+1].size()));g[i+1].push_back(T(1,0,g[i].size()-1));}for(int i = n+2; i <= n+1+m; i++){scanf("%d%d%d",&a,&b,&c);g[a+1].push_back(T(i,INF,g[i].size()));g[i].push_back(T(a+1,0,g[a+1].size()-1));g[b+1].push_back(T(i,INF,g[i].size()));g[i].push_back(T(b+1,0,g[b+1].size()-1));g[i].push_back(T(m+n+2,c,g[m+n+2].size()));g[m+n+2].push_back(T(i,0,g[i].size()-1));sum += c;}N = m+n+2;sap();printf("%d\n",sum - flow);}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
NOI2006 最大獲利(網路流)