HDU 4289:Control(最小割)

http://acm.hdu.edu.cn/showproblem.php?pid=4289

题意:有n个城市,m条无向边,小偷要从s点开始逃到d点,在每个城市安放监控的花费是sa[i],问最小花费可以监控到所有小偷。

思路:求最小割可以转化为最大流。每个城市之间拆点,流量是sa[i],再增加一个超级源点S和s相连,增加一个超级汇点T,让d的第二个点和T相连。然后就可以做了。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <string>
  6 #include <cmath>
  7 #include <queue>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 using namespace std;
 12 #define INF 0x3f3f3f3f
 13 #define N 100010
 14 #define M 510
 15 typedef long long LL;
 16 struct Edge {
 17     int v, nxt, cap;
 18     Edge () {}
 19     Edge (int v, int cap, int nxt) : v(v), cap(cap), nxt(nxt) {}
 20 }edge[N*10];
 21 int head[M], tot, gap[M], dis[M], cur[M], pre[M];
 22 int sa[M], S, T;
 23 
 24 void Add(int u, int v, int cap) {
 25     edge[tot] = Edge(v, cap, head[u]); head[u] = tot++;
 26     edge[tot] = Edge(u, 0, head[v]); head[v] = tot++;
 27 }
 28 
 29 void BFS() {
 30     memset(dis, -1, sizeof(dis));
 31     memset(gap, 0, sizeof(gap));
 32     queue<int> que; que.push(T);
 33     dis[T] = 0; gap[0]++;
 34     while(!que.empty()) {
 35         int u = que.front(); que.pop();
 36         for(int i = head[u]; ~i; i = edge[i].nxt) {
 37             Edge& e = edge[i];
 38             if(~dis[e.v]) continue;
 39             dis[e.v] = dis[u] + 1;
 40             gap[dis[e.v]]++;
 41             que.push(e.v);
 42         }
 43     }
 44 }
 45 
 46 int ISAP(int n) {
 47     BFS(); // 别忘了调用!
 48     memcpy(cur, head, sizeof(cur));
 49     int u = pre[S] = S, ans = 0, i;
 50     while(dis[S] < n) {
 51         if(u == T) {
 52             int flow = INF, index;
 53             for(i = S; i != T; i = edge[cur[i]].v)
 54                 if(flow > edge[cur[i]].cap)
 55                     flow = edge[cur[i]].cap, index = i;
 56             for(i = S; i != T; i = edge[cur[i]].v)
 57                 edge[cur[i]].cap -= flow, edge[cur[i]^1].cap += flow;
 58             u = index; ans += flow;
 59         }
 60         for(i = cur[u]; ~i; i = edge[i].nxt)
 61             if(dis[edge[i].v] == dis[u] - 1 && edge[i].cap > 0) break;
 62         if(~i) {
 63             pre[edge[i].v] = u; cur[u] = i;
 64             u = edge[i].v;
 65         } else {
 66             if(--gap[dis[u]] == 0) break;
 67             int md = n;
 68             for(i = head[u]; ~i; i = edge[i].nxt)
 69                 if(edge[i].cap > 0 && dis[edge[i].v] < md)
 70                     md = dis[edge[i].v], cur[u] = i;
 71             ++gap[dis[u] = md + 1];
 72             u = pre[u];
 73         }
 74     }
 75     return ans;
 76 }
 77 
 78 int main() {
 79     int n, m;
 80     while(~scanf("%d%d", &n, &m)) {
 81         int s, t;
 82         scanf("%d%d", &s, &t);
 83         memset(head, -1, sizeof(head)); tot = 0;
 84         S = 0, T = 2 * n + 1;
 85         // 第一个点是1~n,第二个点是n+1~2*n,第一个点为进来的点,第二个点为出去的点
 86         Add(S, s, INF); Add(t + n, T, INF);
 87         for(int i = 1; i <= n; i++) scanf("%d", &sa[i]);
 88         for(int i = 1; i <= m; i++) {
 89             int u, v;
 90             scanf("%d%d", &u, &v);
 91             Add(u + n, v, INF);
 92             Add(v + n, u, INF);
 93         }
 94         for(int i = 1; i <= n; i++)
 95             Add(i, i + n, sa[i]);
 96         int ans = ISAP(T + 1);
 97         printf("%d
", ans);
 98     }
 99     return 0;
100 }
原文地址:https://www.cnblogs.com/fightfordream/p/6240723.html