POJ 3469 /// 最大流Dinic
阿新 • • 發佈:2018-12-21
題目大意:
N個模組 在核A上執行花費a[i] 在核B上執行花費b[i]
有M個模組組合(d1,d2) 若d1模組與d2模組在不同核上執行需多花費w[i]
求執行所有模組所需的最小花費
挑戰P237
將問題轉化為最小割問題 求得的最小割就是最小花費
那麼記在核A上執行的模組集合為S 核B上執行的模組集合為T 建立源點s 匯點t
某模組在A上執行花費a[i] 則建一條該模組到t容量為a[i]的邊
某模組在B上執行花費b[i] 則建一條s到該模組容量為b[i]的邊
d1模組與d2模組在不同核上執行需多花費w[i] 則建一條d1與d2間容量為w[i]的無向邊
最後求s-t最小割 只要求s到t的最大流就行
#include <stdio.h> #include <algorithm> #include <cstring> #include <vector> #include <queue> #define LL long long #define INF 0x3f3f3f3f using namespace std; const int N=2e4+5; int n,m,s,t; struct NODE { int v,w,r; }; vector <NODE> E[N];View Codevoid addE(int u,int v,int w) { E[u].push_back((NODE){v,w,E[v].size()}); E[v].push_back((NODE){u,w,E[u].size()-1}); } /**Dinic*/ int lev[N], cur[N]; void bfs(int s) { queue <int> q; memset(lev,-1,sizeof(lev)); lev[s]=0; q.push(s); while(!q.empty()) { int u=q.front(); q.pop();for(int i=0;i<E[u].size();i++) { NODE e=E[u][i]; if(e.w>0 && lev[e.v]<0) { lev[e.v]=lev[u]+1; q.push(e.v); } } } } // 廣搜一遍把可走的點分層儲存在lev[]中 int dfs(int s,int t,int f) { if(s==t) return f; // 取地址才能修改到cur[] for(int& i=cur[s];i<E[s].size();i++) { NODE& e=E[s][i]; if(e.w>0 && lev[s]<lev[e.v]) { int d=dfs(e.v,t,min(f,e.w)); if(d>0) { e.w-=d; E[e.v][e.r].w+=d; return d; } } } return 0; } // 深搜找增廣路 int maxFlow(int s,int t) { int flow=0; while(1) { bfs(s); if(lev[t]<0) return flow; memset(cur,0,sizeof(cur)); while(1) { int f=dfs(s,t,INF); if(f==0) break; flow+=f; } } } /***/ int main() { while(~scanf("%d%d",&n,&m)) { s=n, t=s+1; for(int i=0;i<=t;i++) E[i].clear(); for(int i=0;i<n;i++) { int a,b; scanf("%d%d",&a,&b); addE(i,t,a); addE(s,i,b); } for(int i=0;i<m;i++) { int a,b,w; scanf("%d%d%d",&a,&b,&w); addE(a-1,b-1,w); addE(b-1,a-1,w); } printf("%d\n",maxFlow(s,t)); } return 0; }