zoukankan      html  css  js  c++  java
  • 洛谷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
    ", solve());
    264         if(T) {
    265             clear();
    266         }
    267     }
    268     return 0;
    269 }
    AC代码

    找个时间在uoj上A一A。

  • 相关阅读:
    离线安装SilverLight
    Singleton模式
    首次进入
    实现多层菜单(=_=!)(很傻又很土的办法)
    【转】Java中Split函数的用法技巧
    【转】来电显示
    DatePickerDialog
    Unable to resolve target 'android9'
    退出activity的另一种写法
    滚轮控件的定义和使用
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/9747307.html
Copyright © 2011-2022 走看看