zoukankan      html  css  js  c++  java
  • BZOJ4651 & 洛谷1173 & UOJ220:[NOI2016]网格——题解(附debug数据)

    https://www.lydsy.com/JudgeOnline/problem.php?id=4651

    https://www.luogu.org/problemnew/show/P1173#sub

    http://uoj.ac/problem/220

    跳蚤国王和蛐蛐国王在玩一个游戏。
    他们在一个 n 行 m 列的网格上排兵布阵。其中的 c 个格子中 (0≤c≤nm),每个格子有一只蛐蛐,其余的格子中,每个格子有一只跳蚤。
    我们称占据的格子有公共边的两只跳蚤是相邻的。
    我们称两只跳蚤是连通的,当且仅当这两只跳蚤相邻,或存在另一只跳蚤与这两只跳蚤都连通。
    现在,蛐蛐国王希望,将某些(0 个,1 个或多个)跳蚤替换成蛐蛐,使得在此之后存在至少两只跳蚤不连通。
    例如:我们用图表示一只跳蚤,用图表示一只蛐蛐,那么图 1 描述了一个 n=4,m=4,c=2的情况。
    这种情况下蛐蛐国王可以通过将第 2 行第 2 列,和第 3 行第 3 列的两只跳蚤替换为蛐蛐,从而达成他的希望,如图 2 所示。并且,不存在更优的方案,但是可能存在其他替换 2 只跳蚤的方案。
    你需要首先判断蛐蛐国王的希望能否被达成。如果能够达成,你还需要最小化被替换的跳蚤的个数。
     

    这题是一道十分变态的码农分类讨论题。

    参考:https://www.cnblogs.com/ljh2000-jump/p/6373541.html

    显然答案就四种:"-1,0,1,2"。

    -1就是只有一个跳蚤或者只有两个相邻的跳蚤。

    0就是蛐蛐已经把跳蚤分开了。

    1情况思考,我们把相邻的跳蚤连边,如果有割点的话,我们只要在割点处放一个蛐蛐就行了。

    剩下的情况就是2了。

    然而跳蚤的个数有点多,我们只能拿几个跳蚤出来建图跑tarjan。

    一个优秀的方法是拿已放好的蛐蛐为中心5*5的方格内的跳蚤。

    (PS:为什么不拿3*3的呢?因为如果蛐蛐在边界上的话有割点那也是假的,为了防止假割点于是在外围再放一层,思考一下。)

    查找蛐蛐和跳蚤的坐标用map会奇慢(血的教训*1),所以写哈希表存。

    另外,外面一层的跳蚤如果产生割点,同理也是假的,不予理会即可。

    然后就是uoj的hack数据了,这里提供些debug数据,仅供参考。

    3
    1 5 3
    1 1
    1 3
    1 4
    3 5 9
    1 2
    1 3
    1 4
    2 2
    2 3
    2 4
    3 2
    3 3
    3 4
    1 5 3
    1 1
    1 2
    1 5
    
    ans:
    0
    0
    -1
    #include<map>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef double dl;
    const int INF=2e9;
    const int N=1e5+5;
    const int M=N*24;
    const int P=666233;
    const int B=1e9+7;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct Hash{
        int cnt,head[P],nxt[M];
        ll to[M];
        inline void init(){
        cnt=0;memset(head,0,sizeof(head));
        }
        inline void add(ll x,ll y){
        ll v=(x*B+y);int u=v%P;
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
        }
        inline int qry(ll x,ll y){
        ll v=(x*B+y);int u=v%P;
        for(int i=head[u];i;i=nxt[i])
            if(to[i]==v)return i;
        return 0;
        }
    }mp1,mp2;
    struct node{
        int x,y;
    }p[N],q[M];
    int im[M],n,m,c;
    int DX[4]={1,0,-1,0};
    int DY[4]={0,1,0,-1};
    int dx[24]={-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,1,1,1,1,1,2,2,2,2,2};
    int dy[24]={-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,1,2,-2,-1,0,1,2,-2,-1,0,1,2};
    inline dl dis(dl x1,dl y1,dl x2,dl y2){
        dl x=x1-x2,y=y1-y2;
        return sqrt(x*x+y*y);
    }
    struct edge{
        int to,nxt;
    }e[M*4];
    int cnt,head[M],dfn[M],low[M],to[M],id,t,rtson;
    bool cut[M];
    inline void add(int u,int v){
        e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
    }
    void tarjan(int u,int f){
        to[u]=id;dfn[u]=low[u]=++t;
        for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]&&f)cut[u]=1;
            if(!f)rtson++;
        }else if(f!=v)
            low[u]=min(low[u],dfn[v]);
        }
        if(!f&&rtson>=2)cut[u]=1;
    }
    bool vis1[M],vis2[M];
    int dui[M],top;
    inline void init(){
        for(int i=1;i<=mp1.cnt;i++)vis2[i]=0;
        for(int i=1;i<=mp2.cnt;i++)cut[i]=head[i]=low[i]=dfn[i]=to[i]=vis1[i]=0;
        mp1.init();mp2.init();t=cnt=0;
    }
    inline void getnode(int x,int y,int iid){
        vis2[iid]=1;
        for(int i=0;i<4;i++){
        int nx=x+DX[i],ny=y+DY[i];
        if(nx<1||nx>n||ny<1||ny>m)continue;
        int nxtid=mp1.qry(nx,ny);
        if(nxtid)continue;
        int tmp=mp2.qry(nx,ny);
        if(vis1[tmp])continue;
        vis1[tmp]=1;dui[++top]=tmp;
        }
        for(int i=0;i<4;i++){
        int nx=x+DX[i],ny=y+DY[i];
        if(nx<1||nx>n||ny<1||ny>m)continue;
        int nxtid=mp1.qry(nx,ny);
        if(nxtid){
            if(!vis2[nxtid])getnode(nx,ny,nxtid);
            continue;
        }
        }
        for(int i=0;i<4;i++){
        int nx=x+DX[i],ny=y+DY[i];
        if(nx<1||nx>n||ny<1||ny>m)continue;
        vis1[mp2.qry(nx,ny)]=0;
        }
    }
    inline void solve(){
        for(int i=1;i<=mp2.cnt;i++)
        if(!dfn[i]){
            id++;rtson=0;tarjan(i,0);
        }
        for(int i=1;i<=c;i++){
        if(vis2[i])continue;
        top=0;getnode(p[i].x,p[i].y,i);
        for(int j=1;j<=top;j++)
            if(to[dui[j]]!=to[dui[1]]){puts("0");return;}
        }
        if(n==1||m==1){puts("1");return;}
        for(int i=1;i<=mp2.cnt;i++)
        if(cut[i]&&im[i]==1){
            puts("1");return;
        }
        puts("2");
    }
    inline bool find(){
        for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!mp1.qry(i,j)){
            for(int k=0;k<4;k++){
                int x=i+DX[k],y=j+DY[k];
                if(x<1||x>n||y<1||y>m)continue;
                if(!mp1.qry(x,y))return 1;
            }
            return 0;
            }
        }
        }
        return 0;
    }
    int main(){
        int T=read();
        while(T--){
        init();
        n=read(),m=read(),c=read();
        for(int i=1;i<=c;i++){
            p[i].x=read(),p[i].y=read();
            mp1.add(p[i].x,p[i].y);
        }
        if((ll)n*m-c<=1||((ll)n*m-c==2&&find())){puts("-1");continue;}
        for(int i=1;i<=c;i++){
            int x=p[i].x,y=p[i].y;
            for(int j=0;j<24;j++){
            int nx=x+dx[j],ny=y+dy[j];
            if(nx<1||nx>n||ny<1||ny>m||mp1.qry(nx,ny))continue;
            int tmp=mp2.qry(nx,ny);
            if(!tmp){
                mp2.add(nx,ny);
                if(dis(x,y,nx,ny)<1.9)im[mp2.cnt]=1;
                else im[mp2.cnt]=2;
                q[mp2.cnt]=(node){nx,ny};
            }else{
                if(dis(x,y,nx,ny)<1.9)im[tmp]=1;
                else im[tmp]=min(2,im[tmp]);
            }
            }
        }
        for(int i=1;i<=mp2.cnt;i++){
            int x=q[i].x,y=q[i].y;
            for(int j=0;j<4;j++){
            int nx=x+DX[j],ny=y+DY[j];
            if(nx<1||nx>n||ny<1||ny>m)continue;
            int tmp=mp2.qry(nx,ny);
            if(tmp&&im[tmp])add(i,tmp);
            }
        }
        solve();
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    在Unix上使用管道压缩exp导出文件
    自制CPU的黑暗历程一
    Error C1189: #error: Please use the /MD switch for _AFXDLL builds
    Redis乐观锁解决高并发抢红包的问题
    PHP分页类
    汇编基础——使用nasm和bochs学习汇编
    数据同步工具DBsync
    完成端口的一些教程
    sdf
    (转)C#(WIN FORM)两个窗体间LISTVIEW值的修改
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9133880.html
Copyright © 2011-2022 走看看