cychester

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 }
View Code

 

posted on 2018-08-19 20:55  cychester  阅读(112)  评论(0编辑  收藏  举报

导航