[BZOJ4651][NOI2016]网格(Tarjan)
下面直接给出结论,相关证明见官方题解。
1.若跳蚤数不超过1或仅有两只跳蚤且相邻,则答案为-1。
2.若跳蚤形成的连通块个数大于1,则答案为0。
3.若跳蚤之间建图存在割点,则答案为1。
4.否则为2。
这样就有70分了。但是图太大了,显然有很多没用的跳蚤被统计进答案。
考虑到造成不连通的情况一定在蛐蛐附近,于是将每个蛐蛐周围5*5的格子中的24个跳蚤全部取出,内圈8个称为一级空地,外圈称为二级空地。之考虑这些点即可,复杂度就只与蛐蛐个数相关了。
将所有被取出的跳蚤建图,求连通块个数和割点即可。
几个注意点:
1.特判n=1或m=1的情况。
2.只有一级空地与在网格边缘的二级空地成为割点答案才能是0。
3.关于常数问题:不要用memset,判断元素是否存在用S.find(x)!=S.end()不要用S.count(x)。
4.下面代码在UOJ被叉掉了,以及O2会产生各种无解的错误,比如bool tag[N]如果写在int那行的上面就会被系统杀死。
#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mem(a) memset(a,0,sizeof(a))
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
using namespace std; const int N=;
const int dx[]={,,,,-},dy[]={,,,-,};
int T,n,m,c,cnt,tim,nd,id[][],dfn[N],low[N],fa[N],h[N],nxt[N<<],to[N<<];
bool tag[N];
struct P{ int x,y; }p[N],s[];
map<P,int>S;
bool operator <(const P &a,const P &b){ return (a.x==b.x) ? a.y<b.y : a.x<b.x; }
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
int get(int x){ return (fa[x]==x) ? x : fa[x]=get(fa[x]); }
bool chk(int x,int y){ return x>= && x<=n && y>= && y<=m; } inline int rd(){
int x=; char ch=getchar();
while (ch<'' || ch>'') ch=getchar();
while (ch>='' && ch<='') x=(x<<)+(x<<)+(ch^),ch=getchar();
return x;
} bool tarjan(int x,int fa){
dfn[x]=low[x]=++tim; int son=;
For(i,x) if ((k=to[i])!=fa){
if (dfn[k]) low[x]=min(low[x],dfn[k]);
else{
if (tarjan(k,x)) return ;
son++; low[x]=min(low[x],low[k]);
if (((fa && low[k]>=dfn[x]) || (!fa && son>)) && tag[x]) return ;
}
}
return ;
} int main(){
freopen("grid.in","r",stdin);
freopen("grid.out","w",stdout);
for (scanf("%d",&T); T--; ){
scanf("%d%d%d",&n,&m,&c); cnt=; nd=; tim=; S.clear();
rep(i,,c) p[i].x=rd(),p[i].y=rd(),S[p[i]]=-;
if (1ll*n*m-c<=){ puts("-1"); continue; }
if (1ll*n*m-c==){
int tot=;
rep(i,,n) rep(j,,m) if (S.find((P){i,j})==S.end()) s[++tot]=(P){i,j};
if (abs(s[].x-s[].x)+abs(s[].y-s[].y)==) puts("-1"); else puts("");
continue;
}
rep(i,,c){
rep(x,-,) rep(y,-,) if (chk(p[i].x+x,p[i].y+y)){
int x1=p[i].x+x,y1=p[i].y+y;
if (S.find((P){x1,y1})==S.end())
id[x+][y+]=++nd,S[(P){x1,y1}]=nd,tag[nd]=,h[nd]=,dfn[nd]=,fa[nd]=nd;
else id[x+][y+]=S[(P){x1,y1}];
if (x1== || x1==n || y1== || y1==m || (abs(x)<= && abs(y)<=)) tag[id[x+][y+]]=;
}else S[(P){p[i].x+x,p[i].y+y}]=-,id[x+][y+]=-;
rep(x,,) rep(y,,) rep(k,,){
int x1=x+dx[k],y1=y+dy[k];
if (x1< || x1> || y1< || y1> || id[x][y]==- || id[x1][y1]==-) continue;
add(id[x][y],id[x1][y1]);
fa[get(id[x1][y1])]=get(id[x][y]);
}
}
bool flag=;
rep(i,,c){
int t=-;
rep(x,-,) rep(y,-,){
int w=S[(P){p[i].x+x,p[i].y+y}];
if (w==-) continue;
if (t==-) t=get(w); else { if (t!=get(w)){ flag=; break; } }
}
if (flag) break;
}
if (flag){ puts(""); continue; }
if (n== || m==){ puts(""); continue; }
rep(i,,nd) if (!dfn[i] && tarjan(i,)) { puts(""); flag=; break; }
if (!flag) puts("");
}
return ;
}
[BZOJ4651][NOI2016]网格(Tarjan)的更多相关文章
- [UOJ#220][BZOJ4651][Noi2016]网格
[UOJ#220][BZOJ4651][Noi2016]网格 试题描述 跳蚤国王和蛐蛐国王在玩一个游戏. 他们在一个 n 行 m 列的网格上排兵布阵.其中的 c 个格子中 (0≤c≤nm),每个格子有 ...
- BZOJ4651 NOI2016网格(割点)
首先显然可以通过孤立角落里的跳蚤使其不连通,所以只要有解答案就不会大于2.同样显然的一点是当且仅当跳蚤数量<=2且连通时无解.做法其实也很显然了:特判无解,若跳蚤不连通输出0,否则看图中是否无割 ...
- BZOJ4651 & 洛谷1173 & UOJ220:[NOI2016]网格——题解(附debug数据)
https://www.lydsy.com/JudgeOnline/problem.php?id=4651 https://www.luogu.org/problemnew/show/P1173#su ...
- BZOJ4651/UOJ220 [Noi2016]网格
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 并不对劲的bzoj4651:loj2084:uoj220:p1173:[NOI2016]网格
题目大意 有一个\(n*m\)(\(n,m\leq10^9\))的网格,每个格子是空地或障碍(\(障碍数\leq10^5\)) 定义两块空地连通,当且仅当它们是"相邻的两块空地"或 ...
- UOJ#220. 【NOI2016】网格 Tarjan
原文链接www.cnblogs.com/zhouzhendong/p/UOJ220.html 前言 真是一道翔题. 草率题解 -1 的情况很好判,只有两种情况: n * m - c < 2 或者 ...
- [Noi2016]网格
来自FallDream的博客,未经允许,请勿转载,谢谢. 跳蚤国王和蛐蛐国王在玩一个游戏. 他们在一个 n 行 m 列的网格上排兵布阵.其中的 c 个格子中 (0≤c≤nm),每个格子有一只蛐蛐, ...
- 洛谷P1173 [NOI2016]网格
这个码量绝对是业界大毒瘤...... 300行,6.5k,烦的要死...... 题意:给你一个网格图,里面有0或1.你需要把一些0换成1使得存在某两个0不四联通.输出最小的换的数量.无解-1. n,m ...
- UOJ220 [NOI2016] 网格 【割顶】【并查集】
题目分析: 答案显然只有{-1,0,1,2}四种. 对于答案等于-1的情况,只有两种情况,一种是只剩一只跳蚤,另一种是只剩两只跳蚤且他们四连通,这个很好判. 对于答案等于0的情况,那说明联通块大于1, ...
随机推荐
- JavaScript使用数组
for循环遍历 //js的数组里可以存各种类型 var arr =[1,5,true,false,'小明']; //遍历 for(var i=0;i<arr.length;i++){ alert ...
- img图片居中
关键词:clear: both; display: block; margin:auto; 图片居左,居右,居中: /* Alignment */ .alignleft { display ...
- 天梯赛L2-008 最长对称子串 (字符串处理)
对给定的字符串,本题要求你输出最长对称子串的长度.例如,给定"Is PAT&TAP symmetric?",最长对称子串为"s PAT&TAP s&quo ...
- 通过cordova将vue项目打包为webapp
准备工作:需要之前配置好vue-cli脚架构,安装好cordova环境.下面开始对vue.js项目进行打包,打包环境为Android. 可以看下我的github:https://github.com/ ...
- discuz2.5登录后台闪退的解决办法
今天突然发现discuz2.5论坛后台进不去,开始以为密码错了,但发现登录后也是闪退.我试着清除浏览器cookie,也换了其他浏览器也没有用,还是上网找找吧! discuz2.5进入后台闪退的原因: ...
- 商城项目(ssm+dubbo+nginx+mysql统合项目)总结(3)
我不会在这里贴代码和详细步骤什么的,我觉得就算我把它贴出来,你们照着步骤做还是会出很多问题,我推荐你们去看一下黑马的这个视频,我个人感觉很不错,一步一步走下来可以学到很多东西.另外,视频和相关文档的话 ...
- python并发编程之gevent协程(四)
协程的含义就不再提,在py2和py3的早期版本中,python协程的主流实现方法是使用gevent模块.由于协程对于操作系统是无感知的,所以其切换需要程序员自己去完成. 系列文章 python并发编程 ...
- go标识符、变量、常量
标识符 标识符是用来表示Go中的变量名或者函数名,以字母或_开头.后可跟着字母.数字. _ 关键字 关键字是Go语言预先定义好的,有特殊含义的标识符. 变量 1. 语法:var identifier ...
- 浅析busybox如何集成到openwrt
背景 近日添加了一个包到openwrt中,在此过程中又对openwrt多了一些认识 这个包本身自带了kconfig,可直接在这个包里面执行make menuconfig进行配置,然后执行make 但要 ...
- Machine Learning系列--CRF条件随机场总结
根据<统计学习方法>一书中的描述,条件随机场(conditional random field, CRF)是给定一组输入随机变量条件下另一组输出随机变量的条件概率分布模型,其特点是假设输出 ...