HDU 4289 Control【最小割】
题意: 有n个城市,有个小偷想从其中一个城市逃到另一个城市,警察想要堵截这个小偷,知道了在每个城市堵截的成本,问如何安排在哪些城市堵截可以使得
小偷一定会被抓住,而且成本最低。
分析: 最小割模型,城市有成本限制,需要差点来限制,具体建图方法:
将每个城市 i 拆成两个点 i 和 i + n, 之间连一条容量为该点花费的边,
如果 城市 a 和 b 连通,则在 a+n 和 b, b+n 和 a 之间连一条容量为无穷的的边,
这样可以保证最大流量即花费仅受到顶点容量的限制,
如果 起点为 S ,终点为 D ,求出 点S 到 点 D+n 的最大流即为满足条件的最小割。
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<climits> #define min(a,b)(a)<(b)?(a):(b) const int INF=INT_MAX; const int maxn=505; const int maxm=200005; struct node { int from,to,next,c; }e[maxm]; int tot; int head[maxn]; void add(int s,int u,int f1,int f2) { e[tot].from=s; e[tot].to=u; e[tot].c=f1; e[tot].next=head[s]; head[s]=tot++; e[tot].from=u; e[tot].to=s; e[tot].c=f2; e[tot].next=head[u]; head[u]=tot++; } int q[maxn]; int cnt[maxn]; // gap 优化用的统计高度数量的数组 int d[maxn]; // 距离数组 int low[maxn]; // 记录更新增广路上最小流量的数组 int cur[maxn]; // 当前弧数组 int maxflow(int s,int t,int n) { int *front=q,*rear=q; for(int i=1;i<=n;i++) { d[i]=n; cnt[i]=0; } cnt[n]=n-1; cnt[0]++; d[t]=0; *rear++=t; while(front<rear) // 反向广搜,预处理好用于gap优化的 { // 记录高度数量的数组 cnt[] int v=*front++; for(int i=head[v];i!=-1;i=e[i].next) { if(d[e[i].to]==n&&e[i^1].c>0) // 如果没采访过,且有边 { // 相连,入队 d[e[i].to]=d[v]+1; cnt[n]--; cnt[d[e[i].to]]++; *rear++=e[i].to; } } } int flow=0, u=s, top=0; low[0]=INF; for(int i=1;i<=n;i++) cur[i]=head[i]; // 初始化当前弧为第一条邻接边 while(d[s]<n) // 当 d[s]>=n 时,网络出现了gap,增广结束 { int &i=cur[u]; // 当前弧优化 for(;i!=-1;i=e[i].next) // 寻找最短增广路 { if(e[i].c>0&&d[u]==d[e[i].to]+1) // 寻找最短增广路 { low[top+1]=min(low[top],e[i].c);// 更新路径最小流量 q[++top]=i; u=e[i].to; break; } } if(i!=-1) { if(u==t) // 找到了增广路,修改路径上的边容量 { int minf=low[top]; for(int p=1,i;p<=top;++p) { i=q[p]; e[i].c-=minf; e[i^1].c+=minf; } flow+=minf; u=s; low[0]=INF; top=0; } } else { int old_du=d[u]; cnt[old_du]--; d[u]=n-1; for(int i=head[u];i!=-1;i=e[i].next) // 高度数组出现断层 if(e[i].c>0&&d[u]>d[e[i].to]) // 跟新最近的一个点为最短路上的点 d[u]=d[e[i].to]; cnt[++d[u]]++; // 更新高度数量数组 if(d[u]<n) cur[u]=head[u]; if(u!=s) { u=e[q[top]].from; --top; } if(cnt[old_du]==0) // gap 优化 break; } } return flow; } int main() { int n,m,i,j; while(scanf("%d%d",&n,&m)!=EOF) { int S,D; scanf("%d%d",&S,&D); tot=0; memset(head,-1,sizeof(head)); int val; for(i=1;i<=n;i++) { scanf("%d",&val); add(i,i+n,val,0); } int a,b; while(m--) { scanf("%d%d",&a,&b); add(a+n,b,INF,0); add(b+n,a,INF,0); } printf("%d\n",maxflow(S,D+n,n*2)); } return 0; }