bzoj 2574 [Poi1999]Store-Keeper

http://www.elijahqi.win/archives/3584
Description
有一个仓库被分成n*m 个矩形区域,如果两个区域有一条公共边,则被认为这两个区域相邻。包裹都放在一个区域中,剩余的区域或者空闲或者被集装箱占有,这是因为集装箱太重,仓库管理员不能将集装箱搬走。仓库管理员目是是要将包裹从开始的P区域移动到最后的K区域。他可以从空区域走到与之相邻的一个空区域。当仓库管理员走到与包裹相邻的区域时,它可以推动包裹,具体的推动方法如下所示:

读入一个储藏表,开始位置为仓库管理员,最后位置为包裹移动的位置

Input
S – 集装箱,

M –仓库管理员的位置,

P –包裹开始的位置,

K –包裹最后的位置,

w –空区域.

S, M, P 和 K 在文件中只出现一次.

第一行有两个用单个空格分隔的正整数n,m<=100. 接下来是货物存放二维表.共N行,每行为M 个字母组成的单词,字母分别是S, M, P, K, w. 第i单词的第j个位置表示第i行第j列区域的信息,可能是如下内容:

Output
如果包裹不能移动到目的位置,则写入NO。

如果包裹能移动到目的位置,则写入最小的移动次数。

Sample Input
10 12

SSSSSSSSSSSS

SwwwwwwwSSSS

SwSSSSwwSSSS

SwSSSSwwSKSS

SwSSSSwwSwSS

SwwwwwPwwwww

SSSSSSSwSwSw

SSSSSSMwSwww

SSSSSSSSSSSS

SSSSSSSSSSSS

Sample Output
7

HINT
Source

https://blog.csdn.net/elijahqi/article/details/80589454

同上面一篇 只不过这里u求最少步数于是我将visit变成最少需要几步到达那个状态 因为是bfs 保证了最短路到达 为了区分状态 我最后a需要-1

#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define fi first
#define se second
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int N=110;
int dx[]={1,-1,0,0},dy[]={0,0,1,-1};bool vis[N][N];char s[N][N];
int n,m,tot,dfn[N][N],low[N][N],fa[N*N<<1],visit[N][N][4],cnt,id[N][N];
int stx,sty,edx,edy,px,py,top,num;pa q[N*N];
inline void dfs(int x,int y,int frx,int fry){
    dfn[x][y]=low[x][y]=++num;q[++top]=mp(x,y);
    for (int i=0;i<=3;++i){
        int x1=x+dx[i],y1=y+dy[i];
        if (x1<1||x1>n||y1<1||y1>m) continue;
        if (s[x1][y1]!='w') continue;
        if (x1==frx&&y1==fry) continue;
        if (!dfn[x1][y1]){
            dfs(x1,y1,x,y);low[x][y]=min(low[x][y],low[x1][y1]);
            if (low[x1][y1]>=dfn[x][y]){
                ++tot;fa[tot]=id[x][y];static pa v;
                do{
                    v=q[top--];fa[id[v.fi][v.se]]=tot;
                }while(id[v.fi][v.se]!=id[x1][y1]);
            }
        }else low[x][y]=min(low[x][y],dfn[x1][y1]);
    }
}
inline bool check(int x,int y){
    return fa[x]==fa[y]||fa[fa[x]]==y||fa[fa[y]]==x;
}
inline void init(){
    static queue<pa> q;q.push(mp(px,py));vis[px][py]=1;vis[stx][sty]=1;
    while(!q.empty()){
        int x=q.front().fi,y=q.front().se;q.pop();
        for (int i=0;i<=3;++i){
            int x1=x+dx[i],y1=y+dy[i];if (s[x1][y1]!='w') continue;
            if (x1<1||x1>n||y1<1||y1>m) continue;
            if (vis[x1][y1]) continue;vis[x1][y1]=1;q.push(mp(x1,y1));
        }
    }
}
struct node{int x,y,s;};
inline void gao(){
    static queue<node>q;
    for (int i=0;i<=3;++i){
        int x=stx+dx[i],y=sty+dy[i];
        if (x<1||x>n||y<1||y>m) continue;
        if (s[x][y]!='w') continue;if (!vis[x][y]) continue;
        q.push((node){stx,sty,i});visit[stx][sty][i]=1;
    }
    while(!q.empty()){
        static node v;v=q.front();q.pop();
        int x=v.x,y=v.y,S=v.s;
        int x1=x+dx[S^1],y1=y+dy[S^1];
        if (s[x1][y1]=='w'&&!(x1<1||x1>n||y1<1||y1>m)&&!visit[x1][y1][S]){
            visit[x1][y1][S]=visit[x][y][S]+1;q.push((node){x1,y1,S});
        }int nowx=x+dx[S],nowy=y+dy[S];
        for (int i=0;i<=3;++i){
            int x1=x+dx[i],y1=y+dy[i];
            if (x1<1||y1<1||x1>n||y1>m) continue;
            if (s[x1][y1]!='w') continue;
            if (!check(id[x1][y1],id[nowx][nowy])) continue;
            if (visit[x][y][i]) continue;
            visit[x][y][i]=visit[x][y][S]; q.push((node){x,y,i});
        }
    }
}
int main(){
    freopen("bzoj2574.in","r",stdin);
    n=read();m=read();tot=n*m;
    for (int i=1;i<=n;++i) scanf("%s",s[i]+1);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j) {id[i][j]=++cnt;
            if (s[i][j]=='M') px=i,py=j,s[i][j]='w';
            if (s[i][j]=='P') stx=i,sty=j,s[i][j]='w';
            if (s[i][j]=='K') edx=i,edy=j,s[i][j]='w';
        }
    if (stx==edx&&sty==edy) {puts("0");return 0;}
    dfs(px,py,0,0);
    init();
    gao();int ans=0x3f3f3f3f;
    for (int i=0;i<=3;++i){
        if (visit[edx][edy][i]) ans=min(ans,visit[edx][edy][i]);
    }
    if(ans==0x3f3f3f3f) puts("NO");else printf("%d\n",ans-1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值