1. 程式人生 > >POJ 3469 /// 最大流Dinic

POJ 3469 /// 最大流Dinic

題目大意: 

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];
void 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; }
View Code