hdu4289 Control --- 最小割,拆點
阿新 • • 發佈:2017-05-20
|| 每一個 i++ edge 最小割 += tor () string
給一個無向圖。告知敵人的起點和終點。你要在圖上某些點安排士兵。使得敵人不管從哪條路走都必須經過士兵。
每一個點安排士兵的花費不同,求最小花費。
分析:
題意可抽象為,求一些點,使得去掉這些點之後,圖分成了兩部分。敵人的起點和終點分別在這兩部分裏。
即求最小割。
問題是最小割是邊。這裏把點拆成兩個,自己到自己連邊,邊權為該點點權。其它題目給的邊照連就能夠了。
為了方便,對於點i,拆成(i,i+n)。
因此,對於題目給的邊(a,b),就連雙向邊邊:(a+n,b,inf)、(b+n,a,inf)
#include<cstdio> #include<vector> #include<cstring> #include<queue> #define maxn 410 #define inf 0x3f3f3f3f using namespace std; struct node { int from,to,cap,flow; }; struct dinic { int n,m,s,t; vector<node> e; vector<int> g[maxn]; bool vis[maxn]; int d[maxn]; int cur[maxn]; void init(int n) { e.clear(); for(int i=0;i<=n+2;i++) g[i].clear(); } void addedge(int a,int b,int c,int d) { e.push_back((node){a,b,c,0}); e.push_back((node){b,a,d,0}); m=e.size(); g[a].push_back(m-2); g[b].push_back(m-1); } bool bfs() { memset(vis,0,sizeof vis); queue<int> q; q.push(s); d[s]=0; vis[s]=1; while(!q.empty()) { int x=q.front();q.pop(); for(int i=0;i<g[x].size();i++) { node& ee=e[g[x][i]]; if(!vis[ee.to]&&ee.cap>ee.flow) { vis[ee.to]=1; d[ee.to]=d[x]+1; q.push(ee.to); } } } return vis[t]; } int dfs(int x,int a) { if(x==t||a==0) return a; int flow=0,f; for(int& i=cur[x];i<g[x].size();i++) { node& ee=e[g[x][i]]; if(d[x]+1==d[ee.to]&&(f=dfs(ee.to,min(a,ee.cap-ee.flow)))>0) { ee.flow+=f; e[g[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int maxflow(int s,int t) { this->s=s; this->t=t; int flow=0; while(bfs()) { memset(cur,0,sizeof cur); flow+=dfs(s,inf); } return flow; } }; dinic solve; int main() { int i,a,b,st,en,n,m; while(~scanf("%d%d",&n,&m)) { scanf("%d%d",&st,&en); solve.init(n+n); for(i=1;i<=n;i++) { scanf("%d",&a); solve.addedge(i,i+n,a,0); } for(i=0;i<m;i++) { scanf("%d%d",&a,&b); solve.addedge(a+n,b,inf,0); solve.addedge(b+n,a,inf,0); } printf("%d\n",solve.maxflow(st,en+n)); } return 0; }
hdu4289 Control --- 最小割,拆點