【NOI2016】网格

题目描述

输入

输出

样例输入


4 4 2
1 1
4 4
2 3 1
1 2
2 2 2
1 1
2 2
1 1 0

样例输出


2
1
0
-1

分析

我们很容易看出答案只有可能是2,1,0,-1。

关于一些表述的解释

我们将蝈蝈所在格子称为障碍,其余格子称为空地。
根据题意,我们可以看做最外围也是一圈障碍,但是我们不去管它,一下所提到的障碍都不包括外围的一圈。
如果没有特殊指出,连通指的是四连通。
我们根据空地连通性的连通性建图。

  • 如果答案是-1,只有当只有 1 个空地或者只有 2 个相邻的空地。
  • 如果答案是0,就是图中有>1个连通块。
  • 如果答案是1,就是图中有割点。
  • 否则答案是2。

我们定义一级空地为和障碍在八连通意义下直接相连的空地,二级空地为和一级空地在八连通意义下和一级空地直接相连的其他空地,其余的空地就是低级空地。
我们将一级空地和二级空地提出来根据连通性建成新图。
不能只用一级空地建图,否则在判断割点的时候有问题,画图便知。
在新图中怎么判定呢?

  • 如果答案是-1,只有当只有 1 个空地或者只有 2 个相邻的空地。
  • 如果答案是0,就是原图中有>1个空地连通块,也就是空地不能被障碍物分开。在新图中,就是在一个障碍物连通块周围的一级空地必须联通。
  • 如果答案是1,也就是有割点,可以看出原图中割点只能为一级空地,在新图中也就是有割点且割点为一级空地。
  • 否则答案是2。

离散化使用哈希表或者map,时间复杂度 O(nlogn) 或者 O(n)

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<ext/pb_ds/priority_queue.hpp>  
#include<queue>
#include<stack>
#define pointtype int
#define pointtype_INT 1
using namespace std;
typedef long long LL;
typedef pair<int,int>pii;
typedef unsigned uint;
typedef unsigned long long uLL;
const double pi=acos(-1);
template<class T>
void Read(T &x){
    char c;
    bool f(0);
    while(c=getchar(),c!=EOF){
        if(c=='-')
            f=1;
        else if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            if(f)
                x=-x;
            return;
        }
    }
}
struct point{
    pointtype x,y;
    inline point(){
    }
    inline point(pointtype x,pointtype y):x(x),y(y){
    }
    inline point operator-(const point &a)const{
        return point(x-a.x,y-a.y);
    }
    inline bool operator<(const point &b)const{
        if(x==b.x)
            return y<b.y;
        return x<b.x;
    }
    inline bool operator==(const point &b)const{
        return x==b.x&&y==b.y;
    }
    #if pointtype_INT==1
        inline point operator*(const point &a)const{
            return point(1ll*x*a.x-1ll*y*a.y,1ll*x*a.y+1ll*y*a.x);
        }
        inline friend LL cross(const point &a,const point &b){
            return 1ll*a.x*b.y-1ll*a.y*b.x;
        }
        inline friend LL dot(const point &a,const point &b){
            return 1ll*a.x*b.x+1ll*a.y*b.y;
        }
    #else
        inline point operator*(const point &a)const{
            return point(x*a.x-y*a.y,x*a.y+y*a.x);
        }
        inline friend pointtype cross(const point &a,const point &b){
            return a.x*b.y-a.y*b.x;
        }
        inline friend pointtype dot(const point &a,const point &b){
            return a.x*b.x+a.y*b.y;
        }
    #endif
};
//template
#define MAXC 100000
#define MOD 999999
struct hashnode{
    point val;
    int v;
    hashnode *next;
};
inline int& addhash(int u,const point &val,hashnode *&ecnt,hashnode **adj){
    hashnode *p=++ecnt;
    p->val=val;
    p->v=0;
    p->next=adj[u];
    adj[u]=p;
    return p->v;
}
class hash_table{
    public:
    hashnode *adj[MOD],edge[MAXC*24+10],*ecnt;
    int sz;
    inline hash_table():ecnt(edge),sz(0){
        for(int i=0;i<MOD;i++)
            adj[i]=0;
    }
    inline int size(){
        return sz;
    }
    inline hashnode* hash(const point &x){
        int t=(x.x*998244353ll+x.y)%MOD;
        for(hashnode *p=adj[t];p;p=p->next)
            if(p->val==x)
                return p;
        return 0;
    }
    inline int &operator[](const point &x){
        hashnode *p=hash(x);
        if(p)
            return p->v;
        return ++sz,addhash((x.x*998244353ll+x.y)%MOD,x,ecnt,adj);
    }
    inline bool count(const point &x){
        return hash(x);
    }
    inline void clear(){
        ecnt=edge;
        for(int i=0;i<MOD;i++)
            adj[i]=0;
        sz=0;
    }
}pos,vis;
#define tm buyaobaocuo
int n,m,c,cnt,dir[8][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}},viss[MAXC+10],dfnt[MAXC*24+10],dcnt,low[MAXC*24+10],dfn[MAXC*24+10],T,tm;
bool cut,oc[MAXC*24+10];
point fi;
struct node{
    int v;
    node *next;
}*adj[MAXC*24+10],edge[MAXC*24*4+10],*ecnt=edge;
inline void addedge(int u,int v){
    node *p=++ecnt;
    p->v=v;
    p->next=adj[u];
    adj[u]=p;
}
point a[MAXC+10];
void read(){
    Read(n),Read(m),Read(c);
    int i,x,y;
    pos.clear();
    for(i=1;i<=c;i++){
        viss[i]=0;
        Read(x),Read(y);
        a[i]=point(x,y);
        pos[a[i]]=i;
    }
}
void dfs(int u){
    int d;
    viss[u]=1;
    point t;
    for(d=0;d<8;d++){
        t=point(a[u].x+dir[d][0],a[u].y+dir[d][1]);
        if(pos.count(t)){
            if(!viss[pos[t]])
                dfs(pos[t]);
        }
        else if(t.x&&t.y&&t.x<=n&&t.y<=m){
            if(vis.count(t)&&vis[t]!=tm)
                vis.sz++;
            vis[t]=tm;
            if(!fi.x)
                fi=t;
        }
    }
}
int dfs2(const point &x){
    vis[x]=-vis[x];
    int d,ret(1);
    point t;
    for(d=0;d<4;d++){
        t=point(x.x+dir[d][0],x.y+dir[d][1]);
        if(vis.count(t)&&vis[t]==tm)
            ret+=dfs2(t);
    }
    return ret;
}
bool check(){
    vis.clear();
    if(1ll*n*m-c<=1){
        puts("-1");
        return 1;
    }
    if(1ll*n*m-c==2){
        vector<point>b;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(!pos.count(point(i,j)))
                    b.push_back(point(i,j));
        if(abs(b.front().x-b.back().x)+abs(b.front().y-b.back().y)==1){
            puts("-1");
            return 1;
        }
    }
    int i;
    for(i=1;i<=c;i++){
        if(!viss[i]){
            ++tm;
            vis.sz=0;
            fi.x=0;
            dfs(i);
            if(dfs2(fi)!=vis.size()){
                puts("0");
                return 1;
            }
        }
    }
    if(n==1||m==1){
        puts("1");
        return 1;
    }
    return 0;
}
void dfs3(int u,int fa){
    low[u]=dfn[u]=++dcnt;
    int cs(0);
    for(node *p=adj[u];p;p=p->next){
        if(p->v!=fa){
            if(!dfn[p->v]){
                cs++;
                dfs3(p->v,u);
                low[u]=min(low[u],low[p->v]);
                if(low[p->v]>=dfn[u]&&fa&&oc[u])
                    cut=1;
            }
            else
                low[u]=min(low[u],dfn[p->v]);
        }
    }
    if(!fa&&cs>1&&oc[u])
        cut=1;
}
void solve(){
    cut=cnt=dcnt=0;
    ecnt=edge;
    int d,i,dd,cc;
    vis.clear();
    point t,tt;
    for(i=1;i<=c;i++){
        for(d=0;d<8;d++){
            t=point(a[i].x+dir[d][0],a[i].y+dir[d][1]);
            if(t.x&&t.y&&t.x<=n&&t.y<=m&&!pos.count(t)){
                if(!vis.count(t))
                    vis[t]=cc=++cnt;
                else if(oc[cc=vis[t]])
                    continue;
                oc[cc]=1;
                for(dd=0;dd<8;dd++){
                    tt=point(t.x+dir[dd][0],t.y+dir[dd][1]);
                    if(tt.x&&tt.y&&tt.x<=n&&tt.y<=m&&!vis.count(tt)&&!pos.count(tt)){
                        vis[tt]=++cnt;
                        oc[cnt]=0;
                    }
                }
            }
        }
    }
    for(i=1;i<=cnt;i++)
        dfn[i]=0,adj[i]=0;
    for(i=0;i<MOD;i++){
        for(hashnode *p=vis.adj[i];p;p=p->next){
//      for(map<point,int>::iterator j=vis.begin();j!=vis.end();j++){
        //  printf("%d %d\n",j->first.x,j->first.y);
            for(d=0;d<4;d++){
                t=point(p->val.x+dir[d][0],p->val.y+dir[d][1]);
                if(vis.count(t))
                    addedge(p->v,vis[t]);
            }
        }
    }
    for(i=1;i<=cnt;i++)
        if(!dfn[i]){
            dfs3(i,0);
            if(cut){
                puts("1");
                return;
            }
        }
    puts("2");
}
int main()
{
    Read(T);
    while(T--){
        read();
        if(!check())
            solve();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值