[BJOI2006]狼抓兔子
Description
求一个网格图的最小割。
Solution
这个题一看就知道是一个最小割模型,于是就快乐的打了Dinic,也就快乐的TLE了。
查了查资料才知道,这个题要用到对偶图的知识:平面图最小割对应对偶图最短路。所谓对偶图,就是以原图中的面作为点(将s,t连接以将无界区域分成两部分),原图中的边在对偶图中变为连接相邻的面,于是,显然对偶图中s到t的一条路径代表了原图的一个割,最短路径即最小割。
Code
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> const int N = 2000000 + 10; const int M = 6000000 + 10; int hd[N], nxt[M], to[M], w[M], cnt; int n, m, s, t; int dis[N], vis[N]; struct node { int pos, w; node (int a = 0, int b = 0) : pos(a), w(b) {} bool operator < (const node &x) const { return w > x.w; } }; inline void Adde(int x, int y, int z) { cnt++; to[cnt] = y; w[cnt] = z; nxt[cnt] = hd[x]; hd[x] = cnt; } inline void adde(int x, int y, int z) { Adde(x, y, z); Adde(y, x, z); } void dij() { std::priority_queue<node> q; memset(dis, 0x3f, sizeof dis); dis[s] = 0; q.push(node(s, 0)); node tmp; while (!q.empty()) { tmp = q.top(); q.pop(); if (vis[tmp.pos]) continue; vis[tmp.pos] = 1; for (int i = hd[tmp.pos]; i; i = nxt[i]) { if (dis[to[i]] > tmp.w + w[i]) { dis[to[i]] = tmp.w + w[i]; q.push(node(to[i], dis[to[i]])); } } } } int main () { scanf("%d%d", &n, &m); s = 0; t = 2*(n-1)*(m-1)+1; int w; if (n == 1 || m == 1) { if (n > m) std::swap(n, m); int ans = 0x3f3f3f3f; for (int i = 1; i < m; ++i) scanf("%d", &w), ans = std::min(ans, w); printf("%d\n", ans); return 0; } for (int i = 1; i < m; ++i) { scanf("%d", &w); adde(i*2, t, w); } for (int i = 1; i < n-1; ++i) { for (int j = 1; j < m; ++j) { scanf("%d", &w); adde(2*(m-1)*(i-1)+j*2-1, 2*(m-1)*i+j*2, w); } } for (int i = 1; i < m; ++i) { scanf("%d", &w); adde(s, 2*(m-1)*(n-2)+i*2-1, w); } for (int i = 1; i < n; ++i) { scanf("%d", &w); adde(s, 2*(m-1)*(i-1)+1, w); for (int j = 2; j < m; ++j) { scanf("%d", &w); adde(2*(m-1)*(i-1)+j*2-1, 2*(m-1)*(i-1)+j*2-2, w); } scanf("%d", &w); adde(t, 2*(m-1)*i, w); } for (int i = 1; i < n; ++i) { for (int j = 1; j < m; ++j) { scanf("%d", &w); adde(2*(m-1)*(i-1)+j*2, 2*(m-1)*(i-1)+j*2-1, w); } } dij(); printf("%d\n", dis[t]); return 0; }