【题解】P1173 [NOI2016] 网格

一:【题意】

一个 \(n*m\) 的网格, \(c\) 个点是障碍。再放最少的障碍使得存在两个空格子不连通。或者判断无解。

二:【解法】

注意到,答案只会是-1,0,1,2

-1

  • 只有一个空格子,或两个相邻的空格子

0

  • 已有两个不连通空格子
  • 拿出障碍的八联通块,并查集判断

1

  • 存在割点
  • 拿出障碍向外拓展两圈的八联通快,判割点

2

  • 否则为2

三:【代码】

#include<bits/stdc++.h>
#define Pair pair<int,int>
#define x first
#define y second
#define add (int)1e6
#define cl(x,y) ((x-1)*m+y)
using namespace std;
typedef long long LL;
const int N=1e7+10;int n,m,c;
const LL base=1e9+7;
Pair a[N];
bool vis[N];
inline bool checkinf(){
	if(c==n*m) return 1;
	if(c==n*m-1) return 1;
	if(c!=n*m-2) return 0;
	for(int i=1;i<=n*m+10;i++) vis[i]=0;
	for(int i=1;i<=c;i++) vis[cl(a[i].x,a[i].y)]=1;
	int b=clock();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(vis[cl(i,j)]) continue;
			if(i>1&&vis[cl(i-1,j)]==0){
				return 1;
			}
			if(j>1&&vis[cl(i,j-1)]==0){
				return 1;
			}
		}
	}
	return 0;
}
vector<int> mp[N];
unordered_map<LL,int> a_b;
Pair b_a[N];
int idx;
int fa[N];
int siz[N];
inline int find(const int &x){
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}
#define inmap(x,y) (x>0&&x<=n&&y>0&&y<=m)
constexpr int fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
#define hashi(x,y) ((LL)x*base+y)
inline void get_map(const int &up){
	for(int i=1;i<=idx;i++) mp[i].clear();
	a_b.clear();
	for(int i=1;i<=idx;i++) b_a[i]={0,0};
	idx=0;
	
	
	int ttt=0;
	for(int i=1;i<=c;i++) a_b[hashi(a[i].x,a[i].y)]=--ttt;
	for(int i=1;i<=c;i++){
		int x=a[i].x,y=a[i].y;
		for(int dx=-up;dx<=up;dx++){
			for(int dy=-up;dy<=up;dy++){
				if(!dx&&!dy) continue;
			
				int xx=x+dx,yy=y+dy;
				if(!inmap(xx,yy)) continue;	
				if(!a_b.count(hashi(xx,yy))){
					a_b[hashi(xx,yy)]=++idx;
					b_a[idx]={xx,yy};				
				}
			}
		}
	}
	//int b=clock();
	for(int i=1;i<=idx;i++){
		int x=b_a[i].x,y=b_a[i].y;
		for(int j=0;j<4;j++){
			int xx=x+fx[j][0],yy=y+fx[j][1];
			if(!inmap(xx,yy)) continue;
			if(a_b[hashi(xx,yy)]>0){
				mp[i].push_back(a_b[hashi(xx,yy)]);
			}			
		}
	}
	//cout<<"==>"<<idx<<" "<<clock()-b<<"\n";
}
set<int> q;
inline void dfs(const int &x,const int &y){
	int v=a_b[hashi(x,y)];
	if(vis[v+add]) return ;
	vis[v+add]=1;
	if(v>0) q.insert(find(v));
	for(int i=-1;i<=1;i++){
		for(int j=-1;j<=1;j++){
			if(!i&&!j) continue;
			if(i&&j) continue;
			int xx=x+i,yy=y+j;
			if(a_b[hashi(xx,yy)]) dfs(xx,yy);
		}
	}
}
inline bool check0(){
	for(int i=1;i<=idx;i++) siz[fa[i]=i]=1;
	for(int u=1;u<=idx;u++){
		for(auto v:mp[u]){
			int x=u,y=v;
			x=find(x);y=find(y);
			if(x==y) continue;
			if(siz[y]<siz[x]) swap(x,y);
			fa[x]=y;
			siz[y]+=siz[x];
		}
	}
	//for(int i=1;i<=idx;i++) cout<<find(i)<<" ";cout<<"\n"
	for(int i=0;i<=idx+add;i++) vis[i]=0;
	for(int i=1;i<=idx;i++){
		if(vis[i+add]==0){
			q.clear();
			dfs(b_a[i].x,b_a[i].y);
			if(q.size()>1){
				return 1;
			}
		}
	}
	return 0;
}
bool flag;
int dfn[N],low[N],cnt;
inline bool hav(const int &u){
	const int x=b_a[u].x,y=b_a[u].y;
	for(int i=-1;i<=1;i++){
		for(int j=-1;j<=1;j++){
			if(!i&&!j) continue;
			int xx=x+i,yy=y+j;
			if(!inmap(xx,yy)) continue;
			if(a_b[hashi(xx,yy)]<0) return 1;
		}
	}
	return 0;
}
inline void Tarjan(const int &u,const int &pa){
	low[u]=dfn[u]=++cnt;
	int son=0;
	for(auto v:mp[u]){
		if(v==pa) continue;
		if(!dfn[v]){
			son++;
			Tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]&&u!=pa){
				//cout<<"-->"<<b_a[u].x<<" "<<b_a[u].y<<"\n";
				if(hav(u)) flag=1;
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(u==pa){
		if(son>=2){
			//cout<<"-->"<<b_a[u].x<<" "<<b_a[u].y<<"\n";
			if(hav(u)) flag=1;
		}
	}
}
inline bool check1(){
	if(n==1||m==1) return 1;
	flag=0;
	for(int i=1;i<=idx;i++) dfn[i]=low[i]=0;
	cnt=0;
	for(int i=1;i<=idx;i++) {
		if(!dfn[i]){
			Tarjan(i,i);
		}
	}
	return flag;
}
inline void read(int &x){
	char c=getchar_unlocked();
	while(!isdigit(c)) c=getchar_unlocked();
	x=0;
	while(isdigit(c)){
		x=x*10+c-'0';
		c=getchar_unlocked();
	}
}
inline void solve(){
	read(n);read(m);read(c);
	for(int i=1;i<=c;i++){
		read(a[i].x);read(a[i].y);
	}
	get_map(2);
	if(checkinf()) cout<<-1<<"\n";
	else if(check0()) cout<<0<<"\n";
	else if(check1()) cout<<1<<"\n";
	else cout<<2<<"\n";
//	cout<<"-->"<<clock()<<"\n";
	
} 
int main(){
	//freopen("P1173_16.in","r",stdin);
	int t;cin>>t;
	while(t--) solve();
	return 0;
}
posted @ 2026-01-10 09:28  Ming3398  阅读(1)  评论(0)    收藏  举报