刚了几个小时啊,这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)\),还有一点并查集的复杂度。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<cstdlib>
  4. #include<iostream>
  5. #include<algorithm>
  6. #include<cmath>
  7. #include<vector>
  8. #include<queue>
  9. #define pl puts("lala")
  10. #define cp cerr<<"lala"<<endl
  11. #define fi first
  12. #define se second
  13. #define pb push_back
  14. #define ln putchar('\n')
  15. using namespace std;
  16. inline int read()
  17. {
  18. char ch=getchar();int g=1,re=0;
  19. while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
  20. while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
  21. return re*g;
  22. }
  23. typedef long long ll;
  24. typedef pair<int,int> pii;
  25. const int N=100011;
  26. struct HashMap
  27. {
  28. static const int mod=9999991;
  29. static const int bas=1e9+1;
  30. int head[mod+11],cnt;
  31. int stk[1000050],top;
  32. struct node
  33. {
  34. ll key; int next,val;
  35. }e[1000050];
  36. HashMap() {cnt=top=0;}
  37. inline void insert(pii p,int v)
  38. {
  39. ll w=1ll*p.fi*bas+p.se;
  40. int o=w%mod;
  41. for(int i=head[o];i;i=e[i].next) if(e[i].key==w) return ;
  42. e[++cnt]=(node){w,head[o],v}; head[o]=cnt;
  43. stk[++top]=o;
  44. }
  45. inline int operator [] (pii p)
  46. {
  47. ll w=1ll*p.fi*bas+p.se;
  48. int o=w%mod;
  49. for(int i=head[o];i;i=e[i].next) if(e[i].key==w) return e[i].val;
  50. return 0;
  51. }
  52. void clear()
  53. {
  54. cnt=0;
  55. while(top) head[stk[top]]=0,top--;
  56. }
  57. }qid,zid;//q是蛐蛐,z是跳蚤
  58. int move1[8]={0,1,1,1,0,-1,-1,-1}
  59. ,move2[8]={1,1,0,-1,-1,-1,0,1};
  60. int W,H,n,tot=0;
  61. pii p[N],zp[N*10];
  62. bool vis[N];
  63. int head[N*10],cnt=0;
  64. struct node
  65. {
  66. int to,next;
  67. }e[N*25];
  68. inline void add(int x,int y)
  69. {
  70. e[++cnt]=(node){y,head[x]};head[x]=cnt;
  71. }
  72. int dfn[N*10],fa[N];
  73. inline int find(int x)
  74. {
  75. if(fa[x]!=x) return fa[x]=find(fa[x]);
  76. return fa[x];
  77. }
  78. int nfa[9],bel[9];
  79. inline int find2(int x)
  80. {
  81. if(nfa[x]!=x) return nfa[x]=find2(nfa[x]);
  82. return nfa[x];
  83. }
  84. void dfs2(int u)
  85. {
  86. dfn[u]=1;
  87. for(int i=head[u];i;i=e[i].next)
  88. {
  89. int v=e[i].to;
  90. if(dfn[v]) continue;
  91. dfs2(v);
  92. }
  93. }
  94. queue<pii>q;
  95. int stk[N],top=0,bel2[9];
  96. void bfs(int sx,int sy)
  97. {
  98. q.push(pii(sx,sy)); vis[qid[pii(sx,sy)]]=1;
  99. while(!q.empty())
  100. {
  101. int ux=q.front().fi,uy=q.front().se; q.pop();
  102. for(int k=0;k<8;++k)
  103. {
  104. int x=ux+move1[k],y=uy+move2[k];
  105. int ID=qid[pii(x,y)];
  106. if(!ID||vis[ID]) continue;
  107. stk[++top]=ID;
  108. vis[ID]=1; q.push(pii(x,y));
  109. }
  110. }
  111. }
  112. int work(int cas)
  113. {
  114. W=read(); H=read(); n=read();
  115. for(int i=1;i<=n;++i) vis[i]=0;
  116. qid.clear();
  117. for(int i=1;i<=n;++i)
  118. {
  119. p[i].fi=read(),p[i].se=read();
  120. qid.insert(p[i],i);
  121. }
  122. if(1ll*W*H-n<=1) return -1;
  123. if(1ll*W*H-n==2)
  124. {
  125. bool can=1;
  126. for(int i=1;i<=W;++i)
  127. {
  128. for(int j=1;j<=H;++j) if(!qid[pii(i,j)])
  129. {
  130. for(int k=0;k<8;k+=2)
  131. {
  132. int x=i+move1[k],y=j+move2[k];
  133. if(x<1||y<1||x>W||y>H) continue;
  134. if(!qid[pii(x,y)]) {can=0;break;}
  135. }
  136. }
  137. if(!can) break;
  138. }
  139. if(!can) return -1;
  140. }
  141. if(!n)
  142. {
  143. if(W==1||H==1) return 1;
  144. else return 2;
  145. }
  146. for(int dot=1;dot<=n;++dot) if(!vis[dot])
  147. {
  148. top=0; stk[++top]=dot;
  149. bfs(p[dot].fi,p[dot].se);
  150. tot=0; zid.clear();
  151. for(int i=1;i<=top;++i)
  152. {
  153. int x=p[stk[i]].fi,y=p[stk[i]].se;
  154. for(int k=0;k<8;++k)
  155. {
  156. int nx=x+move1[k],ny=y+move2[k];
  157. if(nx<1||ny<1||nx>W||ny>H) continue;
  158. if(!qid[pii(nx,ny)]&&!zid[pii(nx,ny)])
  159. ++tot,zid.insert(pii(nx,ny),tot),zp[tot]=pii(nx,ny);
  160. }
  161. }
  162. cnt=0;
  163. for(int i=1;i<=tot;++i) head[i]=dfn[i]=0;
  164. for(int i=1;i<=tot;++i)
  165. {
  166. int x=zp[i].fi,y=zp[i].se;
  167. for(int k=0;k<8;k+=2)
  168. {
  169. int nx=x+move1[k],ny=y+move2[k];
  170. if(nx<1||ny<1||nx>W||ny>H) continue;
  171. int ID=zid[pii(nx,ny)];
  172. if(ID) add(i,ID);
  173. }
  174. }
  175. int blk=0;
  176. for(int i=1;i<=tot;++i) if(!dfn[i]) blk++,dfs2(i);
  177. if(blk>1) return 0;
  178. }
  179. if(W==1||H==1) return 1;
  180. tot=0; zid.clear();
  181. for(int i=0;i<=n;++i) fa[i]=i;
  182. for(int i=1;i<=n;++i)
  183. {
  184. int x=p[i].fi,y=p[i].se;
  185. for(int k=0;k<8;++k)
  186. {
  187. int nx=x+move1[k],ny=y+move2[k];
  188. if(nx<1||ny<1||nx>W||ny>H)
  189. {
  190. int r1=find(i),r2=find(0);
  191. fa[r1]=r2;
  192. continue;
  193. }
  194. int ID=qid[pii(nx,ny)];
  195. if(!ID&&!zid[pii(nx,ny)])
  196. ++tot,zid.insert(pii(nx,ny),tot),zp[tot]=pii(nx,ny);
  197. else if(ID)
  198. {
  199. int r1=find(i),r2=find(ID);
  200. fa[r1]=r2;
  201. }
  202. }
  203. }
  204. for(int u=1;u<=tot;++u)
  205. {
  206. for(int i=0;i<8;++i) nfa[i]=i,bel[i]=0;
  207. int x=zp[u].fi,y=zp[u].se;
  208. for(int k=0;k<8;++k)
  209. {
  210. int nx=x+move1[k],ny=y+move2[k];
  211. if(nx<1||ny<1||nx>W||ny>H) {bel[k]=find(0);continue;}
  212. int ID=qid[pii(nx,ny)];
  213. if(ID) bel[k]=find(ID);
  214. else bel[k]=-1;
  215. }
  216. for(int k=0;k<8;++k)
  217. {
  218. if(bel[k]!=-1&&bel[k+1&7]!=-1)
  219. {
  220. int r1=find2(k),r2=find2(k+1&7);
  221. nfa[r1]=r2;
  222. }
  223. if(!(k&1)&&bel[k]!=-1&&bel[k+2&7]!=-1)
  224. {
  225. int r1=find2(k),r2=find2(k+2&7);
  226. nfa[r1]=r2;
  227. }
  228. }
  229. for(int i=0;i<8;++i) bel2[i]=find2(i);
  230. for(int i=0;i<8;++i) if(bel[i]!=-1)
  231. {
  232. for(int j=0;j<i;++j) if(bel[j]!=-1)
  233. {
  234. if(bel[i]==bel[j]&&bel2[i]!=bel2[j])
  235. return 1;
  236. }
  237. }
  238. }
  239. return 2;
  240. }
  241. int main()
  242. {
  243. #ifndef ONLINE_JUDGE
  244. freopen("1.in","r",stdin);freopen("1.out","w",stdout);
  245. #endif
  246. int T=read();
  247. for(int cas=1;cas<=T;++cas) printf("%d\n",work(cas));
  248. return 0;
  249. }

uoj220【NOI2016】网格的更多相关文章

  1. BZOJ4651/UOJ220 [Noi2016]网格

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  2. UOJ220 [NOI2016] 网格 【割顶】【并查集】

    题目分析: 答案显然只有{-1,0,1,2}四种. 对于答案等于-1的情况,只有两种情况,一种是只剩一只跳蚤,另一种是只剩两只跳蚤且他们四连通,这个很好判. 对于答案等于0的情况,那说明联通块大于1, ...

  3. [UOJ#220][BZOJ4651][Noi2016]网格

    [UOJ#220][BZOJ4651][Noi2016]网格 试题描述 跳蚤国王和蛐蛐国王在玩一个游戏. 他们在一个 n 行 m 列的网格上排兵布阵.其中的 c 个格子中 (0≤c≤nm),每个格子有 ...

  4. BZOJ4651 & 洛谷1173 & UOJ220:[NOI2016]网格——题解(附debug数据)

    https://www.lydsy.com/JudgeOnline/problem.php?id=4651 https://www.luogu.org/problemnew/show/P1173#su ...

  5. 并不对劲的bzoj4651:loj2084:uoj220:p1173:[NOI2016]网格

    题目大意 有一个\(n*m\)(\(n,m\leq10^9\))的网格,每个格子是空地或障碍(\(障碍数\leq10^5\)) 定义两块空地连通,当且仅当它们是"相邻的两块空地"或 ...

  6. [Noi2016]网格

    来自FallDream的博客,未经允许,请勿转载,谢谢.   跳蚤国王和蛐蛐国王在玩一个游戏. 他们在一个 n 行 m 列的网格上排兵布阵.其中的 c 个格子中 (0≤c≤nm),每个格子有一只蛐蛐, ...

  7. 洛谷P1173 [NOI2016]网格

    这个码量绝对是业界大毒瘤...... 300行,6.5k,烦的要死...... 题意:给你一个网格图,里面有0或1.你需要把一些0换成1使得存在某两个0不四联通.输出最小的换的数量.无解-1. n,m ...

  8. [BZOJ4651][NOI2016]网格(Tarjan)

    下面直接给出结论,相关证明见官方题解. 1.若跳蚤数不超过1或仅有两只跳蚤且相邻,则答案为-1. 2.若跳蚤形成的连通块个数大于1,则答案为0. 3.若跳蚤之间建图存在割点,则答案为1. 4.否则为2 ...

  9. BZOJ4651 NOI2016网格(割点)

    首先显然可以通过孤立角落里的跳蚤使其不连通,所以只要有解答案就不会大于2.同样显然的一点是当且仅当跳蚤数量<=2且连通时无解.做法其实也很显然了:特判无解,若跳蚤不连通输出0,否则看图中是否无割 ...

  10. NOI2016

    luoguP1712 [NOI2016]区间 这是一道送分题. 对于我这种每天抄题解不动脑子思维僵化得厉害的智障选手就是送命题. 一直在想端点排序各种Treap搞... 正解: 已知一些区间,如何判断 ...

随机推荐

  1. ebook下载 | 《 企业高管IT战略指南——企业为何要落地DevOps》

    "当下,企业DevOps转型不仅是IT部门的事情,更是企业高管必须关注的焦点.DevOps是一项需要自上而下推动的变革运动,只有从顶层实施,才能获得成功.本书将介绍企业高管必须了解的,Dev ...

  2. 如何自定义一个Collector

    Collectors类提供了很多方便的方法,假如现有的实现不能满足需求,我们如何自定义一个Collector呢?   Collector接口提供了一个of方法,调用该方法就可以实现定制Collecto ...

  3. Canvas 线性图形(一):路径

    路径的概念 路径是从起始点到结束点之间的连线.个人认为,二维画布中分为线性图形和非线性图形,线性图形包括矩形.直线.曲线.圆形等各种几何图形:非线性图形包括图象.文本.像素.线性图形中又分为路径和非路 ...

  4. [WPF]WPF设置单实例启动

    WPF设置单实例启动 使用Mutex设置单实例启动 using System; using System.Threading; using System.Windows; namespace Test ...

  5. Redis 哨兵机制

    概述 由一个或多个 Sentinel(哨兵)实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的 ...

  6. Minio分布式集群部署——Swarm

    最近研究minio分布式集群部署,发现网上大部分都是单服务器部署,而minio官方在github上现在也只提供了k8s和docker-compose的方式,网上有关与swarm启动minio集群的文章 ...

  7. 定时器控制单只LED灯

    点击查看代码 #include <reg51.h> #define uchar unsigned char #define uint unsigned int sbit LED=P0^0; ...

  8. 第九十六篇:恶补JS基础

    好家伙,来补基础啦,补JS的基础 先来一些概念性的东西 1.什么是JavaScript?  javaScript的简写形式就是JS,一种广泛用于客户端Web开发的脚本语言,常用来给HTML网页添加动态 ...

  9. 【项目实战】kaggle产品分类挑战

    多分类特征的学习 这里还是b站刘二大人的视频课代码,视频链接:https://www.bilibili.com/video/BV1Y7411d7Ys?p=9 相关注释已经标明了(就当是笔记),因此在这 ...

  10. Shell分析日志文件

    文章转载自:https://mp.weixin.qq.com/s/o63aIM2p9rc2OjhxiC6wgA 1.查看有多少个IP访问: awk '{print $1}' log_file|sort ...