BZOJ1163&BZOJ1339[Baltic2008]Mafia——最小割
题目描述
匪徒准备从一个车站转移毒品到另一个车站,警方准备进行布控. 对于每个车站进行布控都需要一定的代价,现在警
方希望使用最小的代价控制一些车站,使得去掉这些车站后,匪徒无法从原定的初始点到达目标点
输入
第一行输入N,M代表车站的总个数,及有多少条双向边连接它们.
2<=n<=200 , 1 <=m<=20000.
第二行给出两个数a,b,代表匪徒的出发点及目标点.1<=a,b<=N,a<>b.
再下来有N行,给出对第i个车站进行布控所需要的Money,其不超过10 000 000
再下来M行,用于描述图的结构.
输出
最少需要多少Money
样例输入
5 6
5 3
2
4
8
3
10
1 5
1 2
2 4
4 5
2 3
3 4
5 3
2
4
8
3
10
1 5
1 2
2 4
4 5
2 3
3 4
样例输出
5
题意就是让删除一些点使得源点和汇点不联通且删除点权和最小,将每个点拆成一个入点和一个出点,两点间边权为原来点的点权,然后建双向边,就把问题转换成了求网络最小割。
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #include<queue> using namespace std; int next[6000001]; int to[6000001]; int val[6000001]; int head[6000001]; int tot=1; int q[6000001]; int n,m; int S,T; int x,y; int k1,k2; int ans; int d[6000001]; const int INF=0x3f3f3f3f; void add(int x,int y,int v) { tot++; next[tot]=head[x]; head[x]=tot; to[tot]=y; val[tot]=v; tot++; next[tot]=head[y]; head[y]=tot; to[tot]=x; val[tot]=0; } bool bfs(int S,int T) { int r=0; int l=0; memset(d,-1,sizeof(d)); q[r++]=S; d[S]=0; while(l<r) { int now=q[l]; for(int i=head[now];i;i=next[i]) { if(d[to[i]]==-1&&val[i]!=0) { d[to[i]]=d[now]+1; q[r++]=to[i]; } } l++; } if(d[T]==-1) { return false; } else { return true; } } int dfs(int x,int flow) { if(x==T) { return flow; } int now_flow; int used=0; for(int i=head[x];i;i=next[i]) { if(d[to[i]]==d[x]+1&&val[i]!=0) { now_flow=dfs(to[i],min(flow-used,val[i])); val[i]-=now_flow; val[i^1]+=now_flow; used+=now_flow; if(now_flow==flow) { return flow; } } } if(used==0) { d[x]=-1; } return used; } void dinic() { while(bfs(S,T)==true) { ans+=dfs(S,0x3f3f3f); } } int main() { scanf("%d%d",&n,&m); scanf("%d%d",&k1,&k2); S=k1; T=n+k2; for(int i=1;i<=n;i++) { scanf("%d",&x); add(i,n+i,x); } for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); add(n+x,y,INF); add(n+y,x,INF); } dinic(); printf("%d",ans); return 0; }