Description
新的技術正衝擊著手機通訊市場,對於各大電訊廠商來說,這既是機遇,更是挑戰。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公司可以有選擇的建立一些中轉站(投入成本),為一些使用者提供服務並獲得收益(獲益之和)。那麼如何選擇最終建立的中轉站才能讓公司的淨獲利最大呢。(淨獲利 = 獲益之和 - 投入成本之和)
Input
輸入檔案中第一行有兩個正整數N和M 。第二行中有N個整數描述每一個通訊中轉站的建立成本,依次為P1, P2, …, PN 。以下M行,第(i + 2)行的三個數Ai, Bi和Ci描述第i個使用者群的資訊。所有變數的含義可以參見題目描述。
Output
你的程式只要向輸出檔案輸出一個整數,表示公司可以得到的最大淨獲利。
Sample Input
5 5
1 2 3 4 5
1 2 3
2 3 4
1 3 3
1 4 2
4 5 3
Sample Output
4
HINT
【範例說明】選擇建立1、2、3號中轉站,則需要投入成本6,獲利為10,因此得到最大收益4。【評分方法】本題沒有部分分,你的程式的輸出只有和我們的答案完全一致才能獲得滿分,否則不得分。【資料規模和約定】 80%的資料中:N≤200,M≤1 000。 100%的資料中:N≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100。
題解
最大閉合權子圖,源點向每個使用者連邊,流量為獲利值,使用者向所需機器連邊,流量無限,機器向匯點連邊,流量為代價,答案為總獲利減最小割。
代碼
#include<bits/stdc++.h>#define inf 0x7fffffff#define N 150005#define M 1000005#define ll long longusing namespace std;inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}int Head[N],ret[M],Next[M],len[M],gap[N];int dis[N],n,m,S,T,tot,cur[N],ans,sum;inline void ins(int u,int v,int w){ ret[++tot]=v;len[tot]=w; Next[tot]=Head[u];Head[u]=tot;}bool bfs(){ for (int i=1;i<=T;i++) dis[i]=-1;queue<int>q; q.push(S);dis[S]=0; while (!q.empty()) { int now=q.front();q.pop(); for (int i=Head[now];i;i=Next[i]) if (dis[ret[i]]==-1&&len[i]) { dis[ret[i]]=dis[now]+1; q.push(ret[i]); } } if (dis[T]==-1) return 0;return 1;}int dfs(int u,int aug){ if (u==T||aug==0) return aug; int flow=0; for (int i=cur[u];i;i=Next[i]) if (dis[ret[i]]==dis[u]+1) { int t=dfs(ret[i],min(aug-flow,len[i])); len[i]-=t;len[i^1]+=t;flow+=t; if(len[i])cur[u]=i; if (flow==aug) return flow; } if (flow==0) dis[u]=-1; return flow;}void dinic(){ while (bfs()) { for (int i=1;i<=T;i++) cur[i]=Head[i]; ans+=dfs(S,inf); }}int isap(int u,int aug){ if (u==T||aug==0) return aug; int min_d=T,flow=0; for (int i=Head[u];i;i=Next[i]) { if (len[i]>0) { if (dis[ret[i]]+1==dis[u]) { int t=isap(ret[i],min(aug-flow,len[i])); len[i]-=t;len[i^1]+=t;flow+=t; } if (flow==aug) return flow; if (dis[S]==T) return flow; min_d=min(min_d,dis[ret[i]]+1); } } if (flow==0) { gap[dis[u]]--; if (gap[dis[u]]==0) dis[S]=T; dis[u]=min_d; gap[dis[u]]++; } return flow;}int main(){ n=read();m=read();S=n+m+1;T=S+1;tot=1; for (int i=1;i<=n;i++) { int w=read(); ins(i+m,T,w);ins(T,i+m,0); } for (int i=1;i<=m;i++) { int a=read(),b=read(),c=read(); sum+=c; ins(S,i,c);ins(i,S,0); ins(i,a+m,inf);ins(a+m,i,0); ins(i,b+m,inf);ins(b+m,i,0); } //dinic(); while (dis[S]!=T) { ans+=isap(S,inf); } printf("%d",sum-ans); return 0;}