[BZOJ4651][NOI2016]网格(Tarjan)
2018-11-06 16:53
381 查看
下面直接给出结论,相关证明见官方题解。
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
如果写在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=3200010; const int dx[5]={0,0,1,0,-1},dy[5]={0,1,0,-1,0}; int T,n,m,c,cnt,tim,nd,id[5][5],dfn ,low ,fa ,h ,nxt[N<<2],to[N<<2]; bool tag ; struct P{ int x,y; }p ,s[3]; 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>=1 && x<=n && y>=1 && y<=m; } inline int rd(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x; } bool tarjan(int x,int fa){ dfn[x]=low[x]=++tim; int son=0; For(i,x) if ((k=to[i])!=fa){ if (dfn[k]) low[x]=min(low[x],dfn[k]); else{ if (tarjan(k,x)) return 1; son++; low[x]=min(low[x],low[k]); if (((fa && low[k]>=dfn[x]) || (!fa && son>1)) && tag[x]) return 1; } } return 0; } 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=0; nd=0; tim=0; S.clear(); rep(i,1,c) p[i].x=rd(),p[i].y=rd(),S[p[i]]=-1; if (1ll*n*m-c<=1){ puts("-1"); continue; } if (1ll*n*m-c==2){ int tot=0; rep(i,1,n) rep(j,1,m) if (S.find((P){i,j})==S.end()) s[++tot]=(P){i,j}; if (abs(s[1].x-s[2].x)+abs(s[1].y-s[2].y)==1) puts("-1"); else puts("0"); continue; } rep(i,1,c){ rep(x,-2,2) rep(y,-2,2) 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+2][y+2]=++nd,S[(P){x1,y1}]=nd,tag[nd]=0,h[nd]=0,dfn[nd]=0,fa[nd]=nd; else id[x+2][y+2]=S[(P){x1,y1}]; if (x1==1 || x1==n || y1==1 || y1==m || (abs(x)<=1 && abs(y)<=1)) tag[id[x+2][y+2]]=1; }else S[(P){p[i].x+x,p[i].y+y}]=-1,id[x+2][y+2]=-1; rep(x,0,4) rep(y,0,4) rep(k,1,4){ int x1=x+dx[k],y1=y+dy[k]; if (x1<0 || x1>4 || y1<0 || y1>4 || id[x][y]==-1 || id[x1][y1]==-1) continue; add(id[x][y],id[x1][y1]); fa[get(id[x1][y1])]=get(id[x][y]); } } bool flag=0; rep(i,1,c){ int t=-1; rep(x,-2,2) rep(y,-2,2){ int w=S[(P){p[i].x+x,p[i].y+y}]; if (w==-1) continue; if (t==-1) t=get(w); else { if (t!=get(w)){ flag=1; break; } } } if (flag) break; } if (flag){ puts("0"); continue; } if (n==1 || m==1){ puts("1"); continue; } rep(i,1,nd) if (!dfn[i] && tarjan(i,0)) { puts("1"); flag=1; break; } if (!flag) puts("2"); } return 0; }
相关文章推荐
- BZOJ4651 NOI2016网格(割点)
- BZOJ4651 & 洛谷1173 & UOJ220:[NOI2016]网格——题解(附debug数据)
- bzoj 4651 网格
- BZOJ 3907: 网格【组合数学】
- 【BZOJ1179】atm,tarjan缩点+最长路径
- bzoj 1123: [POI2008]BLO (tarjan求点双+树形DP)
- BZOJ 1123: [POI2008]BLO tarjan求割点
- 【BZOJ2707】[SDOI2012]走迷宫 Tarjan+拓扑排序+高斯消元+期望
- bzoj 1179: [Apio2009]Atm tarjan
- 【tarjan求割顶】BZOJ2730-[HNOI2012]矿场搭建
- 网格[bzoj3907]
- [BZOJ 1051][HAOI 2006]受欢迎的牛(tarjan缩点)
- BZOJ1924——Tarjan+记搜
- 【BZOJ 1124】[POI2008] 枪战Maf Tarjan+树dp
- bzoj 1797 最小割【最小割】【tarjan】
- [BZOJ2427]软件安装-tarjan强连通+树形背包
- [BZOJ1093][ZJOI2007][Tarjan][DP]最大半联通子图
- bzoj 2427 软件安装 - Tarjan - 树形动态规划
- 【bzoj1179】[Apio2009]Atm Tarjan缩点+Spfa最长路
- bzoj 1565: [NOI2009]植物大战僵尸 (最大权闭合子图+tarjan+拓扑序)