這個碼量絕對是業界大毒瘤......node
300行,6.5k,煩的要死......算法
題意:給你一個網格圖,裏面有0或1。你須要把一些0換成1使得存在某兩個0不四聯通。輸出最小的換的數量。無解-1。ide
n,m<=1e9,網格中1的數量<=1e5,多組數據。spa
首先咱們發現,最多隻要2就好了(圍住一個角落),因此答案是[-1,2]中的整數。code
而後考慮什麼時候爲-1:0的數目小於2或等於2且相連。blog
什麼時候爲0:圖初始就不連通。get
什麼時候爲1:圖中存在割點。string
除此以外就是2了。hash
而後發現圖很大,c很小,考慮離散化。it
而後發現咱們只要把每一個1周圍的點提取出來便可。
提取3×3是錯誤的,有個衆人皆知的樣例:
0 0 0
0 0 0
0 0 1
顯然提取以後會有一個割點在原圖正中間,可是實際上它並非割點。
而後咱們暴力一點,提取5×5便可......
算法流程:提取點,編號。而後判斷聯通性。而後作tarjan,判斷割點。
而後又有好多坑點...好比割點必須在某個1的周圍3×3區域(易證),若是忽視這個就會出現一種毒瘤狀況:
1 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 1
能夠發如今奇怪的地方出現了割點...
而後還要特判,(n - 1)(m - 1) = 0的時候答案不可能爲2。
而後怒寫一天半終於對了,又發現map太慢跑不過......手寫hash。
終於A了....而後uoj平常97分......
[update]如何判斷答案爲0:對那些提取出來的非關鍵點進行並查集。而後枚舉每一個關鍵點連通塊,若是某個關鍵點連通塊連着兩個並查集,答案爲0。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 inline void read(int &x) { 6 x = 0; 7 char c = getchar(); 8 while(c < '0' || c > '9') { 9 c = getchar(); 10 } 11 while(c >= '0' && c <= '9') { 12 x = (x << 3) + (x << 1) + c - 48; 13 c = getchar(); 14 } 15 return; 16 } 17 18 const int N = 100010; 19 const int dx[4] = {0, 1, 0, -1}; 20 const int dy[4] = {1, 0, -1, 0}; 21 22 const int MO = 19260817, B = 998244353; 23 struct POS { 24 int x, y, h; 25 POS(int xx = 0, int yy = 0) { 26 x = xx; 27 y = yy; 28 h = (1ll * x * B + y) % MO; 29 if(h < 0) { 30 h += MO; 31 } 32 } 33 inline bool operator ==(const POS &d) const { 34 return x == d.x && y == d.y; 35 } 36 }; 37 struct Node { 38 int nex, val; 39 POS p; 40 }node[N * 30]; int top; 41 struct MAP { 42 int e[MO]; 43 inline void insert(const POS &d, const int &a) { 44 node[++top].val = a; 45 node[top].nex = e[d.h]; 46 node[top].p = d; 47 e[d.h] = top; 48 return; 49 } 50 inline int find(const POS &d) { // if not exist return 0 51 for(int i = e[d.h]; i; i = node[i].nex) { 52 if(node[i].p == d) { 53 return node[i].val; 54 } 55 } 56 return 0; 57 } 58 inline void clear() { 59 memset(e, 0, sizeof(e)); 60 return; 61 } 62 }mp, use; 63 64 int n, m, c, xi[N], yi[N], tot, num, root; 65 int dfn[N * 25], low[N * 25], vis[N * 25]; 66 bool cut[N * 25], vis_c[N], OK; 67 68 inline void np(int x, int y) { 69 if(!mp.find(POS(x, y)) && !use.find(POS(x, y))) { 70 mp.insert(POS(x, y), ++tot); 71 } 72 return; 73 } 74 75 inline int get(int x, int y) { 76 return mp.find(POS(x, y)); 77 } 78 79 void tarjan(int s, int x, int y) { 80 dfn[s] = low[s] = ++num; 81 int temp = 0; 82 for(int i = 0; i < 4; i++) { 83 int t = get(x + dx[i], y + dy[i]); 84 if(!t) { 85 continue; 86 } 87 if(!dfn[t]) { 88 tarjan(t, x + dx[i], y + dy[i]); 89 low[s] = std::min(low[s], low[t]); 90 if(low[t] >= dfn[s]) { 91 temp++; 92 } 93 } 94 else { 95 low[s] = std::min(low[s], dfn[t]); 96 } 97 } 98 if(temp >= 2 || (temp == 1 && s != root)) { 99 cut[s] = 1; 100 } 101 return; 102 } 103 104 void DFS_1(int s, int x, int y, int temp) { 105 vis[s] = temp; 106 for(int i = 0;i < 4; i++) { 107 int t = get(x + dx[i], y + dy[i]); 108 if(!t) { 109 continue; 110 } 111 if(!vis[t]) { 112 DFS_1(t, x + dx[i], y + dy[i], temp); 113 } 114 } 115 return; 116 } 117 118 bool fd; 119 int number; 120 121 bool DFS_2(int s, int x, int y) { 122 vis_c[s] = 1; 123 for(int i = 0; i < 4; i++) { 124 if(use.find(POS(x + dx[i], y + dy[i]))) { 125 int ed = use.find(POS(x + dx[i], y + dy[i])); 126 if(vis_c[ed]) { 127 continue; 128 } 129 int t = DFS_2(ed, x + dx[i], y + dy[i]); 130 if(!t) { 131 return 0; 132 } 133 } 134 else if(get(x + dx[i], y + dy[i])) { 135 if(!fd) { 136 number = vis[get(x + dx[i], y + dy[i])]; 137 fd = 1; 138 } 139 else if(number != vis[get(x + dx[i], y + dy[i])]) { 140 OK = 0; 141 return 0; 142 } 143 } 144 } 145 return 1; 146 } 147 148 inline bool check() { 149 OK = 1; 150 int temp = 0; 151 for(int i = 1; i <= c; i++) { 152 for(int x = xi[i] - 2; x <= xi[i] + 2; x++) { 153 for(int y = yi[i] - 2; y <= yi[i] + 2; y++) { 154 if(vis_c[i]) { 155 continue; 156 } 157 if(mp.find(POS(x, y)) && !vis[get(x, y)]) { 158 ++temp; 159 DFS_1(get(x, y), x, y, temp); 160 goto f1; 161 } 162 } 163 } 164 f1: 165 if(!vis_c[i]) { 166 fd = 0; 167 DFS_2(i, xi[i], yi[i]); 168 } 169 if(!OK) { 170 break; 171 } 172 } 173 return !OK; 174 } 175 176 inline int solve() { 177 read(n); 178 read(m); 179 read(c); 180 if(!c) { 181 if(n == 1 && m == 1) { 182 return -1; 183 } 184 if(n == 1 || m == 1) { 185 if(n == 2 || m == 2) { 186 return -1; 187 } 188 return 1; 189 } 190 return 2; 191 } 192 for(int i = 1; i <= c; i++) { 193 read(xi[i]); 194 read(yi[i]); 195 use.insert(POS(xi[i], yi[i]), i); 196 } 197 if(c + 1 >= 1ll * n * m) { 198 return -1; 199 } 200 for(int i = 1; i <= c; i++) { 201 for(int x = xi[i] - 2; x <= xi[i] + 2; x++) { 202 for(int y = yi[i] - 2; y <= yi[i] + 2; y++) { 203 if(x > 0 && y > 0 && x <= n && y <= m && (x != xi[i] || y != yi[i])) { 204 np(x, y); 205 } 206 } 207 } 208 } 209 if(check()) { 210 return 0; 211 } 212 if(c + 2 == 1ll * n * m) { 213 return -1; 214 } 215 if(m == 1 || n == 1) { 216 return 1; 217 } 218 for(int i = 1; i <= c; i++) { 219 for(int x = xi[i] - 2; x <= xi[i] + 2; x++) { 220 for(int y = yi[i] - 2; y <= yi[i] + 2; y++) { 221 if(!use.find(POS(x, y))) { 222 root = get(x, y); 223 if(dfn[root]) { 224 continue; 225 } 226 tarjan(root, x, y); 227 } 228 } 229 } 230 } 231 232 for(int i = 1; i <= c; i++) { 233 for(int x = xi[i] - 1; x <= xi[i] + 1; x++) { 234 for(int y = yi[i] - 1; y <= yi[i] + 1; y++) { 235 int s = get(x, y); 236 if(cut[s]) { 237 return 1; 238 } 239 } 240 } 241 } 242 return 2; 243 } 244 245 inline void clear() { 246 mp.clear(); 247 use.clear(); 248 memset(dfn + 1, 0, tot * sizeof(int)); 249 memset(low + 1, 0, tot * sizeof(int)); 250 memset(cut + 1, 0, tot * sizeof(bool)); 251 memset(vis + 1, 0, tot * sizeof(int)); 252 memset(vis_c + 1, 0, c * sizeof(bool)); 253 tot = 0; 254 num = 0; 255 top = 0; 256 return; 257 } 258 259 int main() { 260 int T; 261 read(T); 262 while(T--) { 263 printf("%d\n", solve()); 264 if(T) { 265 clear(); 266 } 267 } 268 return 0; 269 }
找個時間在uoj上A一A。