題意:給定網格圖,有障礙。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 }
hzwer巨佬寫了個隨機排列起點而後貪心的亂搞,竟然有70pts+ %%%