洛谷P1173 [NOI2016]网格

这个码量绝对是业界大毒瘤......

300行,6.5k,烦的要死......

题意:给你一个网格图,里面有0或1。你需要把一些0换成1使得存在某两个0不四联通。输出最小的换的数量。无解-1。

n,m<=1e9,网格中1的数量<=1e5,多组数据。

首先我们发现,最多只要2就行了(围住一个角落),所以答案是[-1,2]中的整数。

然后考虑何时为-1:0的数目小于2或等于2且相连。

何时为0:图初始就不连通。

何时为1:图中存在割点。

除此之外就是2了。

然后发现图很大,c很小,考虑离散化。

然后发现我们只要把每个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 }
AC代码

找个时间在uoj上A一A。

posted @ 2018-10-06 14:29  huyufeifei  阅读(506)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

ReadEra 阅读书籍

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜