[bzoj2574] [Poi1999]Store-Keeper
坑啊。。
膜了半天byvoid大爷的题解。https://www.byvoid.com/blog/poi-1999-mag/?replytocom=1335/
一开始从人的位置bfs一波,看看能走到初始包裹哪些方向上。要注意不能穿过初始包裹...byvoid的标程在处理穿过包裹什么的地方有问题...但数据略弱。
之后如题解所述。
发现自己不会求点双连通分量QAQ。。那部分就抄标程了...
大概就是记录一下当前走过的边,遇到割点就一直出栈...和求强连通分量差不多,就是一个点可能在多个点双里面..这个比较烦
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=10023; 7 const int xx[4]={-1,1,0,0},yy[4]={0,0,-1,1}; 8 struct zs{int too,pre;}e[maxn<<2];int tot,last[maxn]; 9 int too[2333333],pre[2333333],la[maxn],tt,st1[maxn],top,cnt,st2[maxn],uuu[103][103][4][4];bool uu[maxn]; 10 struct poi{int x,y;}S,T,M; 11 struct zs1{int x,y,dir;}dl[maxn<<2]; 12 int dfn[maxn],low[maxn],tim; 13 bool gd[maxn],u[maxn]; 14 int id[103][103],dis[103][103][4],q[maxn]; 15 char mp[103][103]; 16 int i,j,k,n,m,man,st,ed; 17 18 inline void ins(int a,int b){ 19 int i=la[a]; 20 while(i&&too[i]!=b)i=pre[i]; 21 if(i)return; 22 too[++tt]=b,pre[tt]=la[a],la[a]=tt; 23 } 24 inline bool same(int a,int b){ 25 int i;bool flag; 26 for(i=la[a];i;i=pre[i])uu[too[i]]=1; 27 for(i=la[b];i&&!uu[too[i]];i=pre[i]); 28 flag=i!=0; 29 for(i=la[a];i;i=pre[i])uu[too[i]]=0; 30 return flag; 31 } 32 inline bool canget(int x,int y,int dir1,int dir2){ 33 if(!gd[id[x][y]])return 1; 34 if(uuu[x][y][dir1][dir2]<0) 35 return (uuu[x][y][dir1][dir2]=same( id[x+xx[dir1]][y+yy[dir1]] , id[x+xx[dir2]][y+yy[dir2]] )); 36 else return uuu[x][y][dir1][dir2]; 37 } 38 void tarjan(int x,int fa){ 39 dfn[x]=low[x]=++tim;int too,u,v; 40 for(int i=last[x];i;i=e[i].pre)if(dfn[e[i].too]<dfn[x]){ 41 too=e[i].too; 42 if(!dfn[too]){ 43 st1[++top]=x,st2[top]=too; 44 tarjan(too,x),low[x]=min(low[x],low[too]); 45 if(low[too]>=dfn[x]){ 46 gd[x]=1; 47 cnt++; 48 do{ 49 u=st1[top],v=st2[top], 50 ins(u,cnt),ins(v,cnt),top--; 51 }while((u!=x||v!=too)&&(u!=too||v!=x)); 52 } 53 } 54 else low[x]=min(low[x],dfn[e[i].too]); 55 } 56 } 57 58 inline void insert(int a,int b){ 59 e[++tot].too=b,e[tot].pre=last[a],last[a]=tot, 60 e[++tot].too=a,e[tot].pre=last[b],last[b]=tot; 61 } 62 63 inline bool check(int x,int y){return x>0&&y>0&&x<=n&&y<=m&&mp[x][y]!='S';} 64 65 inline void bfs(int s){ 66 int l=0,r=1,i,now;q[1]=s,u[s]=1; 67 while(l<r) 68 for(i=last[now=q[++l]];i;i=e[i].pre)if(!u[e[i].too]&&e[i].too!=st) 69 u[e[i].too]=1,q[++r]=e[i].too; 70 } 71 inline int run(){ 72 int l=0,r=0,i,nx,ny,ndir,ndis,x,y; 73 for(i=0;i<4;i++){ 74 x=S.x+xx[i],y=S.y+yy[i]; 75 if(check(x,y)&&u[id[x][y]])dl[++r]=(zs1){S.x,S.y,i},dis[S.x][S.y][i]=1;//,printf("st:%d,%d\n",x,y); 76 } 77 while(l<r){ 78 l++,nx=dl[l].x,ny=dl[l].y,ndir=dl[l].dir,ndis=dis[nx][ny][ndir]; 79 x=nx+xx[ndir^1],y=ny+yy[ndir^1];//printf("case:%d,%d dis:%d dir:%d\n",nx,ny,ndis,ndir); 80 if(!check(x,y))continue; 81 if(x==T.x&&y==T.y)return ndis; 82 for(i=0;i<4;i++) 83 if(check(x+xx[i],y+yy[i])&&!dis[x][y][i]&&canget( x,y,ndir,i )) 84 dis[x][y][i]=ndis+1,dl[++r]=(zs1){x,y,i}; 85 } 86 return -233; 87 } 88 int main(){ 89 memset(uuu,200,sizeof(uuu)); 90 scanf("%d%d",&n,&m);int tmp=0;tot=1; 91 for(i=1;i<=n;i++){ 92 scanf("%s",mp[i]+1); 93 for(j=1;j<=m;j++)if(mp[i][j]!='S'){ 94 id[i][j]=++tmp; 95 for(k=0;k<4;k+=2){ 96 int x=i+xx[k],y=j+yy[k]; 97 if(check(x,y)) 98 insert(id[i][j],id[x][y]);//,printf("(%d,%d)-->(%d,%d)\n",x,y,i,j); 99 } 100 if(mp[i][j]=='M')man=tmp,M=(poi){i,j}; 101 if(mp[i][j]=='P')st=tmp,S=(poi){i,j}; 102 if(mp[i][j]=='K')ed=tmp,T=(poi){i,j}; 103 } 104 }//return 233; 105 for(i=1;i<=tmp;i++)if(!dfn[i])tarjan(i,0); 106 // for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(id[i][j]){ 107 // if(mp[i][j]!='S')printf("(%d,%d) %d fa:%d\n",i,j,id[i][j],getfa(id[i][j])); 108 // if(gd[id[i][j]])printf(" gd: (%d,%d)\n",i,j); 109 // } 110 bfs(man); 111 int ans=run(); 112 if(ans<0)puts("NO");else printf("%d\n",ans); 113 }