BZOJ1001 洛谷4001 [BJOI2006]狼抓兔子 题解
这个题目有多种解法,这个题也是一个比较经典的题了,正是因为他的多样的做法,这个题主要难在建图和优化,因为这是一个网格图,所以spfa肯定过不去,所以用最短路解法的话,只能用dij,而网络流也是要加上几个必不可少的优化,具体在代码中解释:
代码:
// luogu-judger-enable-o2 #include <bits/stdc++.h> #define M 6000100 #define N 200100 #define inf 1 << 30 using namespace std; queue <int> q; struct cym { int to, next, len; }e[M * 2]; int lin[M * 2], cnt = 1; int n, m, s, t, deep[M]; inline void add(int u, int v, int w) { e[++cnt].to = v; e[cnt].len = w; e[cnt].next = lin[u]; lin[u] = cnt; } inline bool bfs() { int i, now; memset(deep, 0 ,sizeof(deep)); q.push(s); deep[s] = 1; while(!q.empty()) { int now = q.front(); q.pop(); for(int i = lin[now]; i; i = e[i].next) { if(e[i].len && !deep[e[i].to]) { deep[e[i].to] = deep[now] + 1; q.push(e[i].to); } } } if(deep[t] > 0) return 1; return 0; } int dfs(int x, int maxflow)//maxflow是当前最多可以流多少流量 { if(x == t || maxflow == 0) return maxflow; int w, used = 0; for(int i = lin[x]; i; i = e[i].next) { if(deep[e[i].to] == deep[x] + 1 && e[i].len) { w = dfs(e[i].to, min(maxflow - used, e[i].len));//w=这条边权的最小值或当前最多可以流的流量减去当前增广的流量 if(!w)//如果当前不能走了,就把这条路封掉,封掉的方法就是把层数设为0 { deep[e[i].to] = 0; continue; } used += w;//当前可以流的流量 e[i].len -= w; e[i ^ 1].len += w; if(used == maxflow)//相当于当前用光了 ,没有可以增广的流量了 return used; } } if(!used)//used 是现在可以增广的流量 deep[x] = 0; return used; } int dinic() { int ans = 0; while(bfs()) { ans += dfs(s, inf); } return ans; } inline int read() { char ch = getchar(); int x = 0, f = 1; while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); } while('0' <= ch && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int main() { n = read(), m = read(); s = 1, t = n * m; for (int i = 1; i <= n; i++) for (int j = 1; j < m; j++) { int w; w = read(); add ( (i - 1) * m + j, (i - 1) * m + j + 1, w); add ( (i - 1) * m + j + 1, (i - 1) * m + j, w); } for (int i = 1; i < n; i++) for (int j = 1; j <= m; j++) { int w; w = read(); add ( (i - 1) * m + j, (i - 1) * m + j + m, w); add ( (i - 1) * m + j + m, (i - 1) * m + j, w); } for (int i = 1; i < n; i++) for (int j = 1; j < m; j++) { int w; w = read(); add ( (i - 1) * m + j, (i - 1) * m + j + m + 1, w); add ( (i - 1) * m + j + m + 1, (i - 1) * m + j, w); } /* for(int i = 1; i <= cnt; i++) { printf("%d %d %d\n", e[i].to, e[i].len, e[i].next); }*/ printf("%d", dinic()); return 0; }