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\n", ans); 98 } 99 return 0; 100 }
时间: 2024-10-12 18:30:28