bzoj4213 貪吃蛇

題意:給定網格圖,有障礙。html

你要用若干條蛇把全部空地覆蓋起來。ide

知足:每條蛇要麼成環,要麼頭尾都在邊界。spa

若是一條蛇同時知足,那麼算成環。code

要使頭尾都在邊界的蛇最少。htm

解:blog

一開始想用一個流量表明一條蛇,順着這個思路想了好久都沒想出來。最後終於看了題解。get

若是把蛇看作邊,那麼每一個空地都要和旁邊兩個空地相連。或者在邊界。string

而後咱們又能夠黑白染色一波。it

這樣的話,咱們指定流量從白到黑,那麼每一個白色就應該得到兩個流量以便流出去,而每一個黑的要接受兩個流量。io

因此從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 \n", 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+ %%%

相關文章
相關標籤/搜索