周冬的《两极相通——浅析最大最小定理在信息学竞赛中的应用》把方法讲的很详细了。
几点:
1、把平面图G*中每一个面抽象成对偶图G*中的点。
2、平面图包含f个面,设边e分割fi, fj,则连边(fi, fj)。
3、关于如何区分源点和汇点。可以先连接s和t,得到一个附加面。如下图s->4->7->t->s,s*放到附加面中,t*放到无边界的面中,加以区分。
4、建好图后要把(s*, t*)这条边删掉。
5、G的面数等于G*的点数,G*的点数等于G的面数
6、G与G*边数相同 G*中的环对应G中的割一一对应
如图:
hdu 3780
题意是求最小割。直接套网络流模板会TLE。转换成最短路模型然后用dijkstra求解就行,不过dijkstra要优先队列优化。
得到的最短路模型中,点数最多为(n - 1)*n*2 - n*n + 2,边数最多为(n - 1)*n*2*2,注意别MLE;

#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%lld\n", x) #define Read() freopen("data.in", "r", stdin) #define Write() freopen("data.out", "w", stdout); typedef long long LL; const double eps = 1e-6; const double PI = acos(-1.0); const int inf = 0x1F1F1F1F; using namespace std; const int N = 410; int mp[N][N]; class node { public: int to; int val; int next; }g[N*N<<2]; class pnode { public: int num; int len; pnode() {}; pnode(int a, int b) : num(a), len(b) {} bool operator < (const pnode p) const { return this->len > p.len; } }; priority_queue<pnode> q; int head[N*N + 10], t; int dis[N*N + 10]; bool vis[N*N + 10]; int S, T, n; void init() { memset(head, -1, sizeof(head)); t = 0; } void add(int u, int v, int c) { g[t].to = v; g[t].val = c; g[t].next = head[u]; head[u] = t++; g[t].to = u; g[t].val = c; g[t].next = head[v]; head[v] = t++; } int dijkstra(int s, int t) { while(!q.empty()) q.pop(); q.push(pnode(s, 0)); int i, v; pnode u; for(i = 0; i <= t; ++i) { dis[i] = inf; vis[i] = false; } dis[0] = 0; while(!q.empty()) { u = q.top(); q.pop(); if(u.len != dis[u.num]) continue; if(vis[u.num]) continue; vis[u.num] = true; for(i = head[u.num]; i != -1; i = g[i].next) { v = g[i].to; if(dis[v] > u.len + g[i].val) { dis[v] = u.len + g[i].val; q.push(pnode(v, dis[v])); } } } return dis[t]; } int main() { //Read(); int TT, n, i, j, u, S, T; scanf("%d", &TT); while(TT--) { scanf("%d", &n); for(i = 1; i <= n; ++i) { for(j = 1; j <= n; ++j) { scanf("%d", &mp[i][j]); } } init(); S = 0; T = (n - 1)*(n - 1) + 1; for(i = 1; i <= n - 1; ++i) { for(j = 1; j <= n - 1; ++j) { u = (i - 1)*(n - 1) + j; if(i == 1) add(S, u, mp[i][j]); if(j == 1) add(u, T, mp[i][j]); if(i == n - 1) add(u, T, mp[i + 1][j]); if(j == n - 1) add(S, u, mp[i][j + 1]); if(i < n - 1) add(u, u + n - 1, mp[i + 1][j]); if(j < n - 1) add(u, u + 1, mp[i][j + 1]); } } printf("%d\n", dijkstra(S, T)); } return 0; }