【题解】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;
}

浙公网安备 33010602011771号