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的最大流就行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }