NOI 2016 题目选做
作者:互联网
网格
题目描述
解法
首先有一个关键的 \(\tt observation\):答案不会超过 \(2\)(可以直接封锁边界点),那么根据众多 \(\tt CF\) 题目的经验,我们可以直接开始分类讨论:
- 如果只剩一个跳蚤,或者只剩两个跳蚤并且它们联通,那么答案是
-1
- 如果已经存在两个跳蚤不连通,那么答案是
0
- 把相邻的跳蚤连边,如果原图存在割点那么答案是
1
- 否则答案是
2
那么暴力建图可以做到 \(O(nm)\) 的复杂度,一个比较显然的思路是保留每个障碍旁边的若干点,虽然貌似这种做法可以通过官方数据但是很容易被 \(\tt hack\),这里介绍一种不需要特判的优化建图方法,首先我们保留这些点:
- 距离四个角 \(2\times 2\) 范围内的点。
- 和某个障碍物八联通的点。
- 和某个障碍物在同一行\(/\)列,并且自己身处边界的点。
那么对于保留的点,如果两个点在同一行或者同一列并且中间没有障碍物,就连一条边。最后暴力 \(\tt tarjan\) 求割点即可,时间复杂度 \(O(c)\)
正确性证明待补充。
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 10000005;
#define pb push_back
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int T,n,m,c,q,t,cnt,zxy,dfn[M],low[M];
vector<int> g[M];
struct node {int x,y,t;}a[M];
bool cmp1(node a,node b)
{
if(a.x==b.x && a.y==b.y) return a.t<b.t;
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmp2(node a,node b)
{
return a.y==b.y?a.x<b.x:a.y<b.y;
}
void add(int x,int y,int dx,int dy)
{
for(int i=-dx;i<=dx;i++)
for(int j=-dy;j<=dy;j++)
{
int tx=x+i,ty=y+j;
if(tx>=1 && tx<=n && ty>=1 && ty<=m)
a[++t]={tx,ty,0};
}
}
void dfs(int u,int fa)
{
dfn[u]=low[u]=++cnt;int son=0;
for(int v:g[u])
{
if(!dfn[v])
{
dfs(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
if(fa) zxy=1;
else son++;
}
}
else if(v!=fa) low[u]=min(low[u],dfn[v]);
}
if(son>1) zxy=1;
}
void work()
{
n=read();m=read();c=read();q=t=0;
for(int i=1;i<=c;i++)
{
int x=read(),y=read();
add(x,y,1,1);
add(1,y,0,0);add(n,y,0,0);
add(x,1,0,0);add(x,m,0,0);
a[++t]={x,y,-1};
}
add(1,1,2,2);add(1,m,2,2);add(n,1,2,2);add(n,m,2,2);
sort(a+1,a+1+t,cmp1);int pt=0;node ls;
for(int i=1;i<=t;i++)
if(ls.x!=a[i].x || ls.y!=a[i].y)
ls=a[i],a[++pt]=ls;
t=pt;cnt=zxy=0;
for(int i=1;i<=t;i++)
if(a[i].t!=-1) a[i].t=++q;
for(int i=1;i<=q;i++)
dfn[i]=low[i]=0,g[i].clear();
for(int i=2;i<=t;i++)
if(a[i].x==a[i-1].x && a[i].t!=-1 && a[i-1].t!=-1)
g[a[i].t].pb(a[i-1].t),g[a[i-1].t].pb(a[i].t);
sort(a+1,a+1+t,cmp2);
for(int i=2;i<=t;i++)
if(a[i].y==a[i-1].y && a[i].t!=-1 && a[i-1].t!=-1)
g[a[i].t].pb(a[i-1].t),g[a[i-1].t].pb(a[i].t);
if(q<=1 || (q<=2 && !g[1].empty()))
{
puts("-1");
return ;
}
dfs(1,0);
if(cnt<q) puts("0");
else puts(zxy?"1":"2");
}
signed main()
{
T=read();
while(T--) work();
}
标签:选做,NOI,int,tt,read,include,&&,2016,跳蚤 来源: https://www.cnblogs.com/C202044zxy/p/16209723.html