### POI1999.Store-keeper（推箱子）——點雙連通分量+割點+bfs

http://www.bnuoj.com/v3/problem_show.php?pid=21155

https://www.byvoid.com/blog/poi-1999-mag/
byvoid大牛解析

``//並不能AC#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <cstdlib>#include <queue>#define clr(a,b) memset(a,b,sizeof(a))#define rep(i,n) for(int i=0;i<(n);++i)#define rep1(i,a,b) for(int i=(a);i<(b);++i)#define For(i,n) for(int i=0;i<=(n);++i)#define For1(i,a,b) for(int i=(a);i<=(b);++i)#define forever for(;;)const int MAXN = 10010;const int MAXM = 10010;using namespace std;int n,m;char pic[110][110];struct Tarjan {    int low[MAXN],dfn[MAXN],Stack[MAXN],Belong[MAXN];    int top,block;    bool iscut[MAXN];    struct Edge {        int to,Next;    } edge[MAXM<<1];int head[MAXN],tot;    void addedge(int u,int v)    {        edge[tot].to=v;        edge[tot].Next=head[u];        head[u]=tot++;    }    void init()    {        tot=0;        clr(head,0xff);    }    void dfs(int u,int pre,int dth)    {        int v;        low[u]=dfn[u]=dth;        Stack[top++]=u;        int son=0;        for(int i=head[u]; i!=-1; i=edge[i].Next) {            v=edge[i].to;            if(v==pre) continue;            if(!dfn[v]) {                son++;                dfs(v,u,dth+1);                if(low[u]>low[v]) low[u]=low[v];                if(low[v]>=dfn[u]) {                    iscut[u]=true;                    block++;                    int vn;                    forever {                        vn=Stack[--top];                        Belong[vn]=block;                        if(vn==v) break;                    }                }            } else if(low[u]>dfn[v]) low[u]=dfn[v];        }        if(pre<0&&son==1) iscut[u]=false;    }    void solve()    {        clr(dfn,0);        clr(iscut,false);        top=block=0;        rep(i,n*m) {            if(!dfn[i]) dfs(i,-1,1);        }    }}bcc;struct node {    int x,y;};struct state{    node box,h;    int st;    bool operator<(const state&a)const{        return st>a.st;    }};state cur,Next;bool Hash[110][110][4];int dx[]={0,0,1,-1};int dy[]={1,-1,0,0};int sx,sy;bool isnode(int i,int j){    if(pic[i][j]=='w'||pic[i][j]=='P'||pic[i][j]=='M') return true;    return false;}bool isok(int x,int y){    if(x>=0&&x<n&&y>=0&&y<m&&pic[x][y]!='S') return true;    return false;}bool getHash(state cur,int i){    return Hash[cur.box.x][cur.box.y][i];}void setHash(state cur,int i){    Hash[cur.box.x][cur.box.y][i]=true;}bool find(state cur){    if(pic[cur.box.x][cur.box.y]=='K') return true;    return false;}bool is_together(int x1,int y1,int x2,int y2){    if(bcc.Belong[x1*n+y1]==bcc.Belong[x2*n+y2]) return true;    return false;}int box_tonode(state x){    return x.box.x*n+x.box.y;}int h_tonode(state x){    return x.h.x*n+x.h.y;}int fa[MAXN];int find(int x){    return x==fa[x]? x:fa[x]=find(fa[x]);}void unionSet(int a,int b){    int p=find(a),q=find(b);    if(p!=q) fa[p]=q;}int bfs(){    priority_queue<state> q;    q.push(cur);    clr(Hash,false);    int u,v;    while(!q.empty()){        cur=q.top();q.pop();        if(find(cur)) return cur.st;        rep(i,4){            Next=cur;            Next.box.x=cur.box.x+dx[i];            Next.box.y=cur.box.y+dy[i];            Next.st=cur.st+1;            if(!isok(Next.box.x,Next.box.y)) continue;            if(!bcc.iscut[box_tonode(cur)]){                u=h_tonode(cur),v=(cur.box.x-dx[i])*n+cur.box.y-dy[i];                if(find(u)!=find(v)) continue;                if(!getHash(Next,i)){                    Next.h.x=cur.box.x;                    Next.h.y=cur.box.y;                    setHash(Next,i);                    q.push(Next);                }            }            else{                if(!is_together(cur.h.x,cur.h.y,cur.box.x-dx[i],cur.box.y-dy[i])) continue;                if(!getHash(Next,i)){                    Next.h.x=cur.box.x;                    Next.h.y=cur.box.y;                    setHash(Next,i);                    q.push(Next);                }            }        }    }    return -1;}int main(){#ifndef ONLINE_JUDGEfreopen("in.cpp","r",stdin);#endif // ONLINE_JUDGE    int T,u,v,un,vn;    scanf("%d",&T);    while(T--) {        scanf("%d%d",&n,&m);        bcc.init();        For1(i,1,n*m){            fa[i]=i;        }        rep(i,n) scanf("%s",pic[i]);        rep(i,n)rep(j,m-1) {            if(pic[i][j]=='P'){                cur.box.x=i;cur.box.y=j;                cur.st=0;            }            if(pic[i][j]=='M'){                cur.h.x=i,cur.h.y=j;            }            if(isnode(i,j) && isnode(i,j+1)) {                u = i*n+j,v = i*n+j+1;                unionSet(u,v);                bcc.addedge(u,v);                bcc.addedge(v,u);            }        }        rep(i,m)rep(j,n-1) {            if(isnode(j,i)&&isnode(j+1,i)) {                u=j*n+i,v=(j+1)*n+i;                unionSet(u,v);                bcc.addedge(u,v);                bcc.addedge(v,u);            }        }        bcc.solve();        int ans=bfs();        if(ans==-1) puts("NO");        else printf("%d\n",ans);    }    return 0;}``