1. 程式人生 > >[BZOJ4651][NOI2016]網格(Tarjan)

[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那行的上面就會被系統殺死。

 1 #include<map>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define mem(a) memset(a,0,sizeof(a))
 6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 7
#define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 8 using namespace std; 9 10 const int N=3200010; 11 const int dx[5]={0,0,1,0,-1},dy[5]={0,1,0,-1,0}; 12 int T,n,m,c,cnt,tim,nd,id[5][5],dfn[N],low[N],fa[N],h[N],nxt[N<<2],to[N<<2]; 13 bool tag[N]; 14 struct P{ int x,y; }p[N],s[3]; 15 map<P,int
>S; 16 bool operator <(const P &a,const P &b){ return (a.x==b.x) ? a.y<b.y : a.x<b.x; } 17 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 18 int get(int x){ return (fa[x]==x) ? x : fa[x]=get(fa[x]); } 19 bool chk(int x,int y){ return x>=1 && x<=n && y>=1 && y<=m; } 20 21 inline int rd(){ 22 int x=0; char ch=getchar(); 23 while (ch<'0' || ch>'9') ch=getchar(); 24 while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); 25 return x; 26 } 27 28 bool tarjan(int x,int fa){ 29 dfn[x]=low[x]=++tim; int son=0; 30 For(i,x) if ((k=to[i])!=fa){ 31 if (dfn[k]) low[x]=min(low[x],dfn[k]); 32 else{ 33 if (tarjan(k,x)) return 1; 34 son++; low[x]=min(low[x],low[k]); 35 if (((fa && low[k]>=dfn[x]) || (!fa && son>1)) && tag[x]) return 1; 36 } 37 } 38 return 0; 39 } 40 41 int main(){ 42 freopen("grid.in","r",stdin); 43 freopen("grid.out","w",stdout); 44 for (scanf("%d",&T); T--; ){ 45 scanf("%d%d%d",&n,&m,&c); cnt=0; nd=0; tim=0; S.clear(); 46 rep(i,1,c) p[i].x=rd(),p[i].y=rd(),S[p[i]]=-1; 47 if (1ll*n*m-c<=1){ puts("-1"); continue; } 48 if (1ll*n*m-c==2){ 49 int tot=0; 50 rep(i,1,n) rep(j,1,m) if (S.find((P){i,j})==S.end()) s[++tot]=(P){i,j}; 51 if (abs(s[1].x-s[2].x)+abs(s[1].y-s[2].y)==1) puts("-1"); else puts("0"); 52 continue; 53 } 54 rep(i,1,c){ 55 rep(x,-2,2) rep(y,-2,2) if (chk(p[i].x+x,p[i].y+y)){ 56 int x1=p[i].x+x,y1=p[i].y+y; 57 if (S.find((P){x1,y1})==S.end()) 58 id[x+2][y+2]=++nd,S[(P){x1,y1}]=nd,tag[nd]=0,h[nd]=0,dfn[nd]=0,fa[nd]=nd; 59 else id[x+2][y+2]=S[(P){x1,y1}]; 60 if (x1==1 || x1==n || y1==1 || y1==m || (abs(x)<=1 && abs(y)<=1)) tag[id[x+2][y+2]]=1; 61 }else S[(P){p[i].x+x,p[i].y+y}]=-1,id[x+2][y+2]=-1; 62 rep(x,0,4) rep(y,0,4) rep(k,1,4){ 63 int x1=x+dx[k],y1=y+dy[k]; 64 if (x1<0 || x1>4 || y1<0 || y1>4 || id[x][y]==-1 || id[x1][y1]==-1) continue; 65 add(id[x][y],id[x1][y1]); 66 fa[get(id[x1][y1])]=get(id[x][y]); 67 } 68 } 69 bool flag=0; 70 rep(i,1,c){ 71 int t=-1; 72 rep(x,-2,2) rep(y,-2,2){ 73 int w=S[(P){p[i].x+x,p[i].y+y}]; 74 if (w==-1) continue; 75 if (t==-1) t=get(w); else { if (t!=get(w)){ flag=1; break; } } 76 } 77 if (flag) break; 78 } 79 if (flag){ puts("0"); continue; } 80 if (n==1 || m==1){ puts("1"); continue; } 81 rep(i,1,nd) if (!dfn[i] && tarjan(i,0)) { puts("1"); flag=1; break; } 82 if (!flag) puts("2"); 83 } 84 return 0; 85 }