博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ4651 NOI2016网格(割点)
阅读量:4968 次
发布时间:2019-06-12

本文共 2979 字,大约阅读时间需要 9 分钟。

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

  现在的问题是这个图实在是太大了。正常的离散化可能仍然需要留下c2个点。这个时候发现部分分很足于是我们就可以弃疗了。

  比较直观的一点是附近没有蛐蛐的跳蚤不太可能被割开。显然只有周围八连通有蛐蛐的位置才可能成为割点。那么要判断其是否是割点还需要再取周围一圈。所以取出每个蛐蛐的周围两圈跳蚤放在一张图里,之间四连通的连边。此时若有某个蛐蛐周围两圈的跳蚤处于不同连通块,则说明跳蚤本身就不连通;否则tarjan求一发割点就可以了。注意这里割点必须与蛐蛐八连通(或在边界)才是原图的割点,正确性是显然的,但好像没想明白不这么干会有什么问题。

  map被卡常习惯了。bzoj过了,luoguT两个点。

  upd:莫名其妙的把一个完全能用数组的东西用map存了。然后对于点的初始化在新建点的时候进行,不要直接memset。就能过掉了。

#include
#include
#include
#include
#include
#include
#include
using namespace std;#define ll long long#define N 100010char getc(){ char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}int gcd(int n,int m){ return m==0?n:gcd(m,n%m);}int read(){ int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') { if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f;}int T,n,m,c,dfn[N<<5],low[N<<5],cnt,tot,t,p[N<<5],id[5][5],fa[N<<5];bool tag[N<<5];struct data{ int x,y; bool operator <(const data&a) const { return x
f;int wx[4]={ 0,1,0,-1},wy[4]={ 1,0,-1,0};struct data2{ int to,nxt;}edge[N<<7];int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]);}void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}bool tarjan(int k,int from){ dfn[k]=low[k]=++tot;int son=0; for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=from) { if (dfn[edge[i].to]) low[k]=min(low[k],dfn[edge[i].to]); else { if (tarjan(edge[i].to,k)) return 1; son++;low[k]=min(low[k],low[edge[i].to]); if (from!=-1&&low[edge[i].to]>=dfn[k]||son>1&&from==-1) if (tag[k]) return 1; } } return 0;}int main(){#ifndef ONLINE_JUDGE freopen("bzoj4651.in","r",stdin); freopen("bzoj4651.out","w",stdout); const char LL[]="%I64d\n";#else const char LL[]="%lld\n";#endif T=read(); while (T--) { n=read(),m=read(),c=read();f.clear(); for (int i=1;i<=c;i++) a[i].x=read(),a[i].y=read(),f[a[i]]=-1; if (1ll*n*m-c<=1) {cout<<-1<
=1&&a[i].x+x<=n&&a[i].y+y>=1&&a[i].y+y<=m) { if (f.find((data){a[i].x+x,a[i].y+y})==f.end()) f[(data){a[i].x+x,a[i].y+y}]=++cnt,id[x+2][y+2]=cnt,fa[cnt]=cnt,tag[cnt]=p[cnt]=dfn[cnt]=0; else id[x+2][y+2]=f[(data){a[i].x+x,a[i].y+y}]; if (a[i].x+x==1||a[i].x+x==n||a[i].y+y==1||a[i].y+y==m||abs(x)<=1&&abs(y)<=1) tag[id[x+2][y+2]]=1; } else f[(data){a[i].x+x,a[i].y+y}]=-1,id[x+2][y+2]=-1; for (int x=0;x<=4;x++) for (int y=0;y<=4;y++) for (int k=0;k<4;k++) if (x+wx[k]>=0&&x+wx[k]<=4&&y+wy[k]>=0&&y+wy[k]<=4&&~id[x][y]&&~id[x+wx[k]][y+wy[k]]) addedge(id[x][y],id[x+wx[k]][y+wy[k]]),fa[find(id[x+wx[k]][y+wy[k]])]=find(id[x][y]); } bool flag=1; for (int i=1;i<=c;i++) { int t=-1; for (int x=-2;x<=2;x++) for (int y=-2;y<=2;y++) { int p=f[(data){a[i].x+x,a[i].y+y}]; if (~p) if (t==-1) t=find(p);else if (t!=find(p)) {flag=0;break;} } if (!flag) break; } if (!flag) {cout<<0<

 

转载于:https://www.cnblogs.com/Gloid/p/9910325.html

你可能感兴趣的文章
获取单选按钮选中的值
查看>>
oracle 分页
查看>>
助教学期总结
查看>>
绘制基本 图形之矩形与多边形
查看>>
3-day3-list-truple-map.py
查看>>
02: djangorestframework使用
查看>>
Edit控件显示多行文字
查看>>
JS第二周
查看>>
dataTable.NET的search box每輸入一個字母進行一次檢索的問題
查看>>
Python 文件处理
查看>>
邻接表详解
查看>>
服务器一:分布式服务器结构
查看>>
迭代dict的value
查看>>
eclipse package,source folder,folder区别及相互转换
查看>>
Py 可能是最全面的 python 字符串拼接总结(带注释版)
查看>>
(转载)博弈汇总【巴什博奕,威佐夫博弈,尼姆博弈,斐波那契博弈】
查看>>
《Java程序设计实验》 软件工程18-1,3 OO实验2
查看>>
【Herding HDU - 4709 】【数学(利用叉乘计算三角形面积)】
查看>>
【7-9 有重复的数据I (20 分)】【此题卡输入,需要自己写个输入挂】
查看>>
JRebel安装部署,激活
查看>>