BZOJ 3171[TJOI2013] 循环格 - 费用流
题解
刚开始我也没看出来是个网络流QAQ,觉得还是有点难想:(
要满足每一个点都在一个循环内, 必须满足每个点出度和入度为1。
所以将每个点拆成两个点, 一个点为与S相连, 另一个点与T相连, 容量为1,费用为0。
然后每个点向它指向的点连容量为1, 费用为0的边, 向周围的其他点连容量为1, 费用为1的点
这样建图保证了最大流为点数, 也即每个点入度都为1。
跑费用流就可以算出答案。
代码
1 #include<cstring> 2 #include<queue> 3 #include<cstdio> 4 #include<algorithm> 5 #define rd read() 6 #define rep(i,a,b) for( int i = (a); i <= (b); ++i) 7 #define per(i,a,b) for( int i = (a); i >= (b); --i) 8 using namespace std; 9 10 const int N = 1e4; 11 const int inf = 1061109567; 12 13 int head[N], S, T = N - 1, dis[N], n, m, tot, pre[N], minco, maxflow, vis[N]; 14 int dx[4] = {0, 0, -1, 1}, dy[4] = {1, -1, 0, 0}; 15 16 char s[20]; 17 18 queue<int> q; 19 20 struct edge { 21 int nxt, val, to, c; 22 }e[N << 1]; 23 24 int read() { 25 int X = 0, p = 1;char c = getchar(); 26 for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 27 for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 28 return X * p; 29 } 30 31 int ch(int x) { 32 return ((x + 1) ^ 1) - 1; 33 } 34 35 int tn(int x, int y) { 36 return x * m + y + 1; 37 } 38 39 void added(int fr, int to, int val, int c) { 40 e[++tot].to = to; 41 e[tot].val = val; 42 e[tot].c = c; 43 e[tot].nxt = head[fr]; 44 head[fr] = tot; 45 } 46 47 void add(int fr, int to, int val, int c) { 48 added(fr, to, val, c); 49 added(to, fr, 0, -c); 50 } 51 52 int bfs() { 53 memset(dis, 63, sizeof(dis)); 54 memset(pre, 0, sizeof(pre)); 55 memset(vis, 0, sizeof(vis)); 56 q.push(S); 57 dis[S] = 0; 58 for(int u, nt; !q.empty(); ) { 59 u = q.front(); q.pop(); 60 for(int i = head[u]; i; i = e[i].nxt) { 61 nt = e[i].to; 62 if(dis[nt] <= dis[u] + e[i].c || !e[i].val) continue; 63 dis[nt] = dis[u] + e[i].c; 64 pre[nt] = i; 65 if(!vis[nt]) vis[nt] = 1, q.push(nt); 66 } 67 vis[u] = 0; 68 } 69 return dis[T]; 70 } 71 72 void EK() { 73 for(; bfs() != inf; ) { 74 int tmp = inf; 75 for(int i = pre[T]; i; i = pre[e[ch(i)].to]) tmp = min(tmp, e[i].val); 76 for(int i = pre[T]; i; i = pre[e[ch(i)].to]) e[i].val -= tmp, e[ch(i)].val += tmp; 77 maxflow += tmp; 78 minco += tmp * dis[T]; 79 } 80 } 81 82 int main() 83 { 84 n = rd; m = rd; 85 rep(i, 0, n - 1) { 86 scanf("%s", s); 87 rep(j, 0, m - 1) { 88 rep(k, 0, 3) { 89 int nx = (i + dx[k]) % n, ny = (j + dy[k]) % m; 90 nx = (nx + n) % n; ny = (ny + m) % m; 91 add(tn(i, j), tn(nx, ny) + n * m, 1, 1); 92 } 93 int flag; 94 if(s[j] == 'U') flag = 2; 95 if(s[j] == 'D') flag = 3; 96 if(s[j] == 'L') flag = 1; 97 if(s[j] == 'R') flag = 0; 98 int nx = (i + dx[flag]) % n, ny = (j + dy[flag]) % m; 99 nx = (nx + n) % n; ny = (ny + m) % m; 100 add(tn(i, j), tn(nx, ny) + n * m, 1, 0); 101 } 102 } 103 rep(i, 0, n - 1) rep(j, 0, m - 1) { 104 add(S, tn(i, j), 1, 0); 105 add(tn(i, j) + n * m, T, 1, 0); 106 } 107 EK(); 108 printf("%d\n", minco); 109 }