zoukankan      html  css  js  c++  java
  • 【NOI2016】网络

    题面

    https://www.luogu.org/problem/P1173

    题解

    终于调出来了呢。

    这道题和【NOI2015】小园丁和老司机一样,都是码量大的神仙题,不过写小园丁和老司机的时候,没有花太长时间调试,但是这题...真的是自闭了。

    首先,答案肯定在$-1$,$0$,$1$,$2$之间。

    你可能觉得我在耍流氓,因为我看了题解,现在我就来证明答案一定小于等于$2$。

    我们只考虑围住一个白棋子的四周,它就孤立了,所以答案肯定小于等于$4$。

    我们肯定在图中找一个“气”数最小的点围住,我用反证法,让我构造一个棋局,使每个点的气数都大于等于$3$。

    我们考虑黑棋和白棋相接触处的轮廓线,对于和黑棋相接触的白棋,假设它下面是黑棋,下一个白棋只有两种放置方式

    • 向右,形成一条直线。
    • 向下,拐个弯。

    这个过程是不能停下来的,因为一旦停下来,就露出了破绽,使得气数为$2$。

    所以这个轮廓线会最终形成一个螺旋,只有一个无限大的二维空间才能放下这个无限大的螺旋,所以不存在,假设不成立,原命题得证。

    我们把长宽至少有一个为$1$的特判掉。

    再一个结论,当长宽都至少为$2$时,任意一种切割,都是两个或两个以上的黑棋形成的,这是一个显然的结论,但是是本题的突破口。

    我们把一个黑棋上下左右形成的$5 imes 5$方块里棋子挖出来建图,因为只要它们是有用的。

    如果对于一个黑棋的联通块,它旁边的白棋分别属于不同的联通块,则此黑棋的联通块把白棋的联通块切割了,输出$0$。

    如果图中存在割点(且割点旁边$3 imes 3$的区域内有黑棋),则输出$1$。

    反之,则输出$2$。

    我们要支持从集合内插入元素,$O(1)$查找,确定集合中元素的$id$,用$hash$表实现(用$sort$建边亦可,但是八个$cmp$八个$sort$有点麻烦)

    $hash$函数肯定是我们最喜欢的$1000000007$啦,奇怪了,不是我最喜欢的吗?

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #define ri register int
    #define N 2500500
    using namespace std;
    
    const int dx[4]={0,-1,0,1},dy[4]={1,0,-1,0};
    int dfn[N],low[N],col[N],root,n,m,c,ccol;
    vector<int> to[N];
    bool del[N],can;
    bool vi[100050],vvv[N];
    int cc,co;
    int x[N],y[N],id[N];
    
    void add_edge(int u,int v) {
      to[u].push_back(v); 
      to[v].push_back(u);
    }
    
    bool cmp(int a,int b) {
      return x[a]<x[b] || x[a]==x[b] && y[a]<y[b];
    }
    
    struct hash_table{
      #define SIZ 1233107
      vector<int> h[SIZ];
      void clear() {
        for (ri i=0;i<SIZ;i++) h[i].clear();
      }
      void add(int cx,int cy,int s) {
        int g=((cx*1LL*1000000007)%SIZ+cy)%SIZ;
        for (ri i=0;i<h[g].size();i++) if (x[h[g][i]]==cx && y[h[g][i]]==cy) {
          if (s) del[h[g][i]]=1;
          return;
        }
        h[g].push_back(++cc);
        x[cc]=cx; y[cc]=cy;
        if (s) del[cc]=1;
        return;
      }
      int find(int cx,int cy) {
        int g=((cx*1LL*1000000007)%SIZ+cy)%SIZ;
        for (ri i=0;i<h[g].size();i++) if (x[h[g][i]]==cx && y[h[g][i]]==cy) return h[g][i];
        return 0;
      }
    } H;
    
    void init() {
      H.clear();
      for (ri i=1;i<=cc;i++) to[i].clear();
      for (ri i=1;i<=cc;i++) del[i]=0;
      for (ri i=1;i<=cc;i++) dfn[i]=low[i]=0;
      cc=0; co=0; can=0;
    }
    
    bool check(int u) {
      for (ri dx=-1;dx<=1;dx++)
        for (ri dy=-1;dy<=1;dy++) {
          if (del[H.find(x[u]+dx,y[u]+dy)]) return 1;
        }
      return 0;
    }
    
    void tarjan(int u,int ccc) {
      dfn[u]=low[u]=++co; col[u]=ccc;
      int rs=0;
      for (ri i=0;i<to[u].size();i++) {
        int v=to[u][i];
        if (!dfn[v]) {
          rs++;
          tarjan(v,ccc);
          low[u]=min(low[u],low[v]);
          if (low[v]>=dfn[u] && u!=root && check(u)) can=1;
        }
        else {
          low[u]=min(low[u],dfn[v]);
        }
      }
      if (u==root && rs>=2 && check(u)) can=1;
    }
    
    int num(int x,int y) {return (x-1)*m+y;}
    bool checkf1() {
      memset(vi,0,sizeof(vi));
      for (ri i=1;i<=cc;i++) if (del[i]) vi[num(x[i],y[i])]=1;
      for (ri i=1;i<=n;i++)
        for (ri j=1;j<=m;j++) if (!vi[num(i,j)]) {
          if (i+1<=n && !vi[num(i+1,j)]) return 1;
          if (j+1<=m && !vi[num(i,j+1)]) return 1;
        }
      return 0;
    }
    
    bool bfs(int cur) {
      vvv[cur]=1;
      int cx=x[cur],cy=y[cur];
      for (ri i=0;i<4;i++) {
        int nx=cx+dx[i],ny=cy+dy[i];
        if (nx<1 || nx>n || ny<1 || ny>m) continue;
        int t=H.find(nx,ny);
        if (!del[t]) {
          if (ccol==-1) ccol=col[t];
          if (col[t]!=ccol) return 0;
        }
        else {
          if (!vvv[t] && !bfs(t)) return 0;
        }
      }
      return 1;
    }
    
    bool dfs() {
      memset(vvv,0,sizeof(vvv));
      for (ri i=1;i<=cc;i++) if (del[i] && !vvv[i]) {
        ccol=-1;
        if (!bfs(i)) return 1;
      }
      return 0;
    }
    
    int a[100050];
    int solve() {
      int cn=0;
      if (m==1) {
        for (ri i=1;i<=cc;i++) if (del[i]) a[++cn]=x[i];
      }
      else {
        for (ri i=1;i<=cc;i++) if (del[i]) a[++cn]=y[i];
      }
      sort(a+1,a+cn+1);
      a[0]=0; if (m==1) a[cn+1]=n+1; else a[cn+1]=m+1;
      int cnt=0;
      for (ri i=0;i<=cn;i++) if (a[i]+1!=a[i+1]) cnt++;
      if (cnt==1) return 1; else return 0;
    }
    
    int main() {
      int T,t,tx,ty;
      scanf("%d",&T);
      while (T--) {
        init();
        scanf("%d %d %d",&n,&m,&c);
        for (ri i=1;i<=c;i++) {
          scanf("%d %d",&tx,&ty);
          for (ri dx=-2;dx<=2;dx++)
            for (ri dy=-2;dy<=2;dy++) {
              if (tx+dx<1 || tx+dx>n || ty+dy<1 || ty+dy>m) continue;
              if (dx==0 && dy==0) H.add(tx+dx,ty+dy,1); else H.add(tx+dx,ty+dy,0);
            }
        }
        for (ri i=1;i<=cc;i++) id[i]=i;
        sort(id+1,id+cc+1,cmp);
        for (ri i=1;i<=cc;i++) if (!del[id[i]]) {
          t=H.find(x[id[i]]+1,y[id[i]]+0); if (t&&!del[t]) add_edge(id[i],t);
          t=H.find(x[id[i]]+0,y[id[i]]+1); if (t&&!del[t]) add_edge(id[i],t);
        }
        can=0;
        int ccc=0;
        for (ri i=1;i<=cc;i++) if (!del[i] && !dfn[i]) root=i,tarjan(i,++ccc);
        if (n*1LL*m-c<=1 || n*1LL*m-c==2 && checkf1()) puts("-1");
        else if (n==1 || m==1) printf("%d
    ",solve());
        else if (dfs()) puts("0");
        else if (can) puts("1");
        else puts("2");
      }
      return 0;
    }
  • 相关阅读:
    Java安装以及环境变量配置
    IPython绘图和可视化---matplotlib
    Tensorboard可视化(关于TensorFlow不同版本引起的错误)
    Tensorboard可视化
    关于Tensorflow安装opencv和pygame
    perl将json转换成xml
    cnblogs终于把以前内容的管理权还给我了~
    final评论2
    final评论1
    psp
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11407802.html
Copyright © 2011-2022 走看看