uoj220【NOI2016】网格
刚了几个小时啊,这tm要是noi我怕不是直接滚粗了。我判答案为1的情况试了几种做法,最后终于想到了一个靠谱的做法,然后细节巨多,调了好久,刚拿到97分时代码有6.2KB了,后来发现有些东西好像没啥用就删到了5KB了,然后发现hack数据T掉了,就写了个哈希表换掉了map才过...真累
对了,我最开始判1是先求的割点再判断,只不过我感觉好像没有必要求割点啊,直接判也是对的,就把那段删掉了,然后在uoj上可以过,但别人貌似大多都求了割点?也许我这样做相当于求了割点?
讲做法吧(可能还有一些细节没考虑到,欢迎hack):
两蛐蛐的格子有公共点则称他们相邻(即一只蛐蛐可能和8只蛐蛐相邻),跳蚤则是有公共边(4条)。
答案肯定<=2,因为肯定存在一只在角落上的跳蚤。
判-1:\(nm-c=0 \ or\ nm-c=1 \ or\ (nm-c=2并且这两个跳蚤相邻)\)
判0:考虑每个有蛐蛐组成的连通块,对这里面的每只蛐蛐都把它8个方向的跳蚤拿出来,跳蚤们互相连边,答案为0当且仅当这里跳蚤组成的连通块个数>1.
判1:将边界视作一只假蛐蛐,然后对于所有的真假蛐蛐两两相邻则连边,对于所有的真蛐蛐都把它8个方向的跳蚤拿出来,对于某只跳蚤,把它替换成蛐蛐能达成目标当且仅当加入了它后附近的蛐蛐形成了环且环内部有跳蚤(就是枚举\(C_8^2\)种组合判)。具体的话,形成了环很好判看在不在一个连通块里就行了,至于环内部有没有跳蚤,由于环内部肯定有一只跳蚤是和新加入的这只蛐蛐相邻的,你只要判 在只考虑新蛐蛐的相邻点的情况下,这两只蛐蛐是否处于一个连通块内,不是说明肯定加入这只蛐蛐后就可以达成目标了。
举两个例子(网格从1开始编号,0代表跳蚤,1代表蛐蛐):
00000
01110
01000
01000
00000
你要判断(3,3)这个位置替换成蛐蛐可不可以,当你加入这只蛐蛐时,枚举到了(4,2)与(2,4)这两只蛐蛐,发现他们形成了环(但它包不住任意一只跳蚤),然后在只考虑这个方阵的情况下:
111
100
100
那两个点已经在一个连通块内了,不行。
00100
00100
00000
00100
00100
你要判断(3,3)这个位置替换成蛐蛐可不可以,当你加入这只蛐蛐时,枚举到了(2,3)与(4,3)这两只蛐蛐,发现他们形成了环,然后在只考虑这个方阵的情况下:
010
000
010
那两个点不在一个连通块内,加入蛐蛐后,左右就是完全隔开的两个跳蚤连通块了。因此可以。
最后剩余的情况就是2了。
然后中间要一些n=0 or W=1 or H=1的情况要小心。
复杂度是\(O(C_8^2n+8nlogn)\),用哈希表的话就是\(O(C_8^2n+8n)\),还有一点并查集的复杂度。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define pl puts("lala")
#define cp cerr<<"lala"<<endl
#define fi first
#define se second
#define pb push_back
#define ln putchar('\n')
using namespace std;
inline int read()
{
char ch=getchar();int g=1,re=0;
while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
return re*g;
}
typedef long long ll;
typedef pair<int,int> pii;
const int N=100011;
struct HashMap
{
static const int mod=9999991;
static const int bas=1e9+1;
int head[mod+11],cnt;
int stk[1000050],top;
struct node
{
ll key; int next,val;
}e[1000050];
HashMap() {cnt=top=0;}
inline void insert(pii p,int v)
{
ll w=1ll*p.fi*bas+p.se;
int o=w%mod;
for(int i=head[o];i;i=e[i].next) if(e[i].key==w) return ;
e[++cnt]=(node){w,head[o],v}; head[o]=cnt;
stk[++top]=o;
}
inline int operator [] (pii p)
{
ll w=1ll*p.fi*bas+p.se;
int o=w%mod;
for(int i=head[o];i;i=e[i].next) if(e[i].key==w) return e[i].val;
return 0;
}
void clear()
{
cnt=0;
while(top) head[stk[top]]=0,top--;
}
}qid,zid;//q是蛐蛐,z是跳蚤
int move1[8]={0,1,1,1,0,-1,-1,-1}
,move2[8]={1,1,0,-1,-1,-1,0,1};
int W,H,n,tot=0;
pii p[N],zp[N*10];
bool vis[N];
int head[N*10],cnt=0;
struct node
{
int to,next;
}e[N*25];
inline void add(int x,int y)
{
e[++cnt]=(node){y,head[x]};head[x]=cnt;
}
int dfn[N*10],fa[N];
inline int find(int x)
{
if(fa[x]!=x) return fa[x]=find(fa[x]);
return fa[x];
}
int nfa[9],bel[9];
inline int find2(int x)
{
if(nfa[x]!=x) return nfa[x]=find2(nfa[x]);
return nfa[x];
}
void dfs2(int u)
{
dfn[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(dfn[v]) continue;
dfs2(v);
}
}
queue<pii>q;
int stk[N],top=0,bel2[9];
void bfs(int sx,int sy)
{
q.push(pii(sx,sy)); vis[qid[pii(sx,sy)]]=1;
while(!q.empty())
{
int ux=q.front().fi,uy=q.front().se; q.pop();
for(int k=0;k<8;++k)
{
int x=ux+move1[k],y=uy+move2[k];
int ID=qid[pii(x,y)];
if(!ID||vis[ID]) continue;
stk[++top]=ID;
vis[ID]=1; q.push(pii(x,y));
}
}
}
int work(int cas)
{
W=read(); H=read(); n=read();
for(int i=1;i<=n;++i) vis[i]=0;
qid.clear();
for(int i=1;i<=n;++i)
{
p[i].fi=read(),p[i].se=read();
qid.insert(p[i],i);
}
if(1ll*W*H-n<=1) return -1;
if(1ll*W*H-n==2)
{
bool can=1;
for(int i=1;i<=W;++i)
{
for(int j=1;j<=H;++j) if(!qid[pii(i,j)])
{
for(int k=0;k<8;k+=2)
{
int x=i+move1[k],y=j+move2[k];
if(x<1||y<1||x>W||y>H) continue;
if(!qid[pii(x,y)]) {can=0;break;}
}
}
if(!can) break;
}
if(!can) return -1;
}
if(!n)
{
if(W==1||H==1) return 1;
else return 2;
}
for(int dot=1;dot<=n;++dot) if(!vis[dot])
{
top=0; stk[++top]=dot;
bfs(p[dot].fi,p[dot].se);
tot=0; zid.clear();
for(int i=1;i<=top;++i)
{
int x=p[stk[i]].fi,y=p[stk[i]].se;
for(int k=0;k<8;++k)
{
int nx=x+move1[k],ny=y+move2[k];
if(nx<1||ny<1||nx>W||ny>H) continue;
if(!qid[pii(nx,ny)]&&!zid[pii(nx,ny)])
++tot,zid.insert(pii(nx,ny),tot),zp[tot]=pii(nx,ny);
}
}
cnt=0;
for(int i=1;i<=tot;++i) head[i]=dfn[i]=0;
for(int i=1;i<=tot;++i)
{
int x=zp[i].fi,y=zp[i].se;
for(int k=0;k<8;k+=2)
{
int nx=x+move1[k],ny=y+move2[k];
if(nx<1||ny<1||nx>W||ny>H) continue;
int ID=zid[pii(nx,ny)];
if(ID) add(i,ID);
}
}
int blk=0;
for(int i=1;i<=tot;++i) if(!dfn[i]) blk++,dfs2(i);
if(blk>1) return 0;
}
if(W==1||H==1) return 1;
tot=0; zid.clear();
for(int i=0;i<=n;++i) fa[i]=i;
for(int i=1;i<=n;++i)
{
int x=p[i].fi,y=p[i].se;
for(int k=0;k<8;++k)
{
int nx=x+move1[k],ny=y+move2[k];
if(nx<1||ny<1||nx>W||ny>H)
{
int r1=find(i),r2=find(0);
fa[r1]=r2;
continue;
}
int ID=qid[pii(nx,ny)];
if(!ID&&!zid[pii(nx,ny)])
++tot,zid.insert(pii(nx,ny),tot),zp[tot]=pii(nx,ny);
else if(ID)
{
int r1=find(i),r2=find(ID);
fa[r1]=r2;
}
}
}
for(int u=1;u<=tot;++u)
{
for(int i=0;i<8;++i) nfa[i]=i,bel[i]=0;
int x=zp[u].fi,y=zp[u].se;
for(int k=0;k<8;++k)
{
int nx=x+move1[k],ny=y+move2[k];
if(nx<1||ny<1||nx>W||ny>H) {bel[k]=find(0);continue;}
int ID=qid[pii(nx,ny)];
if(ID) bel[k]=find(ID);
else bel[k]=-1;
}
for(int k=0;k<8;++k)
{
if(bel[k]!=-1&&bel[k+1&7]!=-1)
{
int r1=find2(k),r2=find2(k+1&7);
nfa[r1]=r2;
}
if(!(k&1)&&bel[k]!=-1&&bel[k+2&7]!=-1)
{
int r1=find2(k),r2=find2(k+2&7);
nfa[r1]=r2;
}
}
for(int i=0;i<8;++i) bel2[i]=find2(i);
for(int i=0;i<8;++i) if(bel[i]!=-1)
{
for(int j=0;j<i;++j) if(bel[j]!=-1)
{
if(bel[i]==bel[j]&&bel2[i]!=bel2[j])
return 1;
}
}
}
return 2;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);freopen("1.out","w",stdout);
#endif
int T=read();
for(int cas=1;cas<=T;++cas) printf("%d\n",work(cas));
return 0;
}