bzoj4213 贪吃蛇

题意:给定网格图,有障碍。

你要用若干条蛇把所有空地覆盖起来。

满足:每条蛇要么成环,要么头尾都在边界。

如果一条蛇同时满足,那么算成环。

要使头尾都在边界的蛇最少。

解:

一开始想用一个流量代表一条蛇,顺着这个思路想了很久都没想出来。最后终于看了题解。

如果把蛇看做边,那么每个空地都要和旁边两个空地相连。或者在边界。

然后我们又可以黑白染色一波。

这样的话,我们指定流量从白到黑,那么每个白色就应该获得两个流量以便流出去,而每个黑的要接受两个流量。

所以从s向白连流量限制为[2, 2]的边,黑色向t同样。

白向相邻黑连流量限制[0, 1]的边。

边界怎么处理?白向t连[0, 1],费用为1的边。s向黑同样。

然后求有源汇有上下界最小费用可行流即可。

输出答案时要/2,因为头尾各算了一次。

  1 /**************************************************************
  2     Problem: 4213
  3     Language: C++
  4     Result: Accepted
  5     Time:144 ms
  6     Memory:32128 kb
  7 ****************************************************************/
  8  
  9 #include <cstdio>
 10 #include <algorithm>
 11 #include <queue>
 12 #include <cstring>
 13 #include <string>
 14  
 15 const int N = 1000, M = 1000010, INF = 0x3f3f3f3f;
 16 const int dx[] = {0, 1, 0, -1};
 17 const int dy[] = {1, 0, -1, 0};
 18  
 19 struct Edge {
 20     int nex, v, c, len;
 21 }edge[M << 1]; int top = 1;
 22  
 23 int e[N], d[N], vis[N], pre[N], flow[N], G[20][20], m, n, lm, ot[N];
 24 std::queue<int> Q;
 25 char str[20];
 26  
 27 inline void add(int x, int y, int z, int w) {
 28     top++;
 29     edge[top].v = y;
 30     edge[top].c = z;
 31     edge[top].len = w;
 32     edge[top].nex = e[x];
 33     e[x] = top;
 34  
 35     top++;
 36     edge[top].v = x;
 37     edge[top].c = 0;
 38     edge[top].len = -w;
 39     edge[top].nex = e[y];
 40     e[y] = top;
 41     return;
 42 }
 43  
 44 inline bool SPFA(int s, int t) {
 45     memset(d, 0x3f, sizeof(d));
 46     d[s] = 0;
 47     flow[s] = INF;
 48     vis[s] = 1;
 49     Q.push(s);
 50     while(!Q.empty()) {
 51         int x = Q.front();
 52         Q.pop();
 53         vis[x] = 0;
 54         for(int i = e[x]; i; i = edge[i].nex) {
 55             int y = edge[i].v;
 56             if(edge[i].c && d[y] > d[x] + edge[i].len) {
 57                 d[y] = d[x] + edge[i].len;
 58                 pre[y] = i;
 59                 flow[y] = std::min(flow[x], edge[i].c);
 60                 if(!vis[y]) {
 61                     vis[y] = 1;
 62                     Q.push(y);
 63                 }
 64             }
 65         }
 66     }
 67     return d[t] < INF;
 68 }
 69  
 70 inline void update(int s, int t) {
 71     int temp = flow[t];
 72     while(t != s) {
 73         int i = pre[t];
 74         edge[i].c -= temp;
 75         edge[i ^ 1].c += temp;
 76         t = edge[i ^ 1].v;
 77     }
 78     return;
 79 }
 80  
 81 inline int solve(int s, int t, int &cost) {
 82     int ans = 0;
 83     cost = 0;
 84     while(SPFA(s, t)) {
 85         ans += flow[t];
 86         cost += flow[t] * d[t];
 87         update(s, t);
 88     }
 89     return ans;
 90 }
 91  
 92 inline int id(int x, int y, int f = 0) {
 93     int ans = (x - 1) * m + y;
 94     return ans;
 95 }
 96  
 97 inline void judge(int x) {
 98     for(int i = e[x]; i; i = edge[i].nex) {
 99         if(edge[i].c) {
100             printf("ss -> %d  c = %d 
", edge[i].v, edge[i].c);
101         }
102     }
103     return;
104 }
105  
106 int main() {
107  
108     int i = 0, sum = 0;
109     while(scanf("%s", str + 1) != EOF) {
110         i++;
111         m = strlen(str + 1);
112         for(int j = 1; j <= m; j++) {
113             G[i][j] = (str[j] == '#');
114         }
115     }
116     n = i;
117     lm = n * m;
118     int s = lm + 1, t = lm + 2, ss = lm + 3, tt = lm + 4;
119     for(i = 1; i <= n; i++) {
120         for(int j = 1; j <= m; j++) {
121             if(G[i][j]) {
122                 continue;
123             }
124             if((i + j) & 1) {
125                 // s - 2 > (i, j)
126                 add(ss, id(i, j), 2, 0);
127                 sum += 2;
128                 ot[s] += 2;
129                 for(int k = 0; k < 4; k++) {
130                     int x = i + dx[k];
131                     int y = j + dy[k];
132                     if(x && y && x <= n && y <= m && !G[x][y]) {
133                         add(id(i, j), id(x, y), 1, 0);
134                     }
135                 }
136                 if(i == 1 || j == 1 || i == n || j == m) {
137                     add(id(i, j), t, 1, 1);
138                 }
139             }
140             else {
141                 // (i, j) - 2 > t
142                 add(id(i, j), tt, 2, 0);
143                 ot[t] -= 2;
144                 if(i == 1 || j == 1 || i == n || j == m) {
145                     add(s, id(i, j), 1, 1);
146                 }
147             }
148  
149         }
150     }
151     add(s, tt, ot[s], 0);
152     add(ss, t, -ot[t], 0);
153     add(t, s, INF, 0);
154     sum += -ot[t];
155     int ans;
156  
157     if(solve(ss, tt, ans) != sum) {
158         puts("-1");
159         return 0;
160     }
161     printf("%d", ans / 2);
162     return 0;
163 }
AC代码

hzwer巨佬写了个随机排列起点然后贪心的乱搞,居然有70pts+ %%%

原文地址:https://www.cnblogs.com/huyufeifei/p/10099420.html