BZOJ[1671][Usaco2005 Dec]Knights of Ni 骑士 Floodfill

题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=1671

Description

贝茜遇到了一件很麻烦的事:她无意中闯入了森林里的一座城堡,如果她想回家,就必须穿过这片由骑士们守护着的森林.为了能安全地离开,贝茜不得不按照骑士们的要求,在森林寻找一种特殊的灌木并带一棵给他们.当然,贝茜想早点离开这可怕的森林,于是她必须尽快完成骑士们给的任务,贝茜随身带着这片森林的地图,地图上的森林被放入了直角坐标系,并按x,y轴上的单位长度划分成了W×H(1≤W,H≤1000)块,贝茜在地图上查出了她自己以及骑士们所在的位置,当然地图上也标注了她所需要的灌木生长的区域.某些区域是不能通过的(比如说沼泽地,悬崖,以及食人兔的聚居地).在没有找到灌木之前,贝茜不能通过骑士们所在的那个区域,为了确保她自己不会迷路,贝茜只向正北、正东、正南、正西四个方向移动(注意,她不会走对角线).她要走整整一天,才能从某块区域走到与它相邻的那块区域. 输入数据保证贝茜一定能完成骑士的任务.贝茜希望你能帮她计算一下,她最少需要多少天才可脱离这可怕的地方?
Input

第1行输入2个用空格隔开的整数,即题目中提到的W、H.
接下来输入贝茜持有的地图,每一行用若干个数字代表地图上对应行的地形.第1行描述了地图最北的那一排土地;最后一行描述的则是最南面的.相邻的数字所对应的区域是相邻的.如果地图的宽小于或等于40,那每一行数字恰好对应了地图上的一排土地.如果地图的宽大于40,那每行只会给出40个数字,并且保证除了最后一行的每一行都包含恰好40个数字.没有哪一行描述的区域分布在两个不同的行里.
地图上的数字所对应的地形:
0:贝茜可以通过的空地
1:由于各种原因而不可通行的区域
2:贝茜现在所在的位置
3:骑士们的位置
4:长着贝茜需要的灌木的土地

Output

输出一个正整数D,即贝茜最少要花多少天才能完成骑士们给的任务.

Sample Input

8 4
4 1 0 0 0 0 1 0
0 0 0 1 0 1 0 0
0 2 1 1 3 0 4 0
0 0 0 4 1 1 1 0

Sample Output

11

HINT
这片森林的长为8,宽为4.贝茜的起始位置在第3行,离骑士们不远.

贝茜可以按这样的路线完成骑士的任务:北,西,北,南,东,东,北,东,东,南,南.她在森林的西北角得到一株她需要的灌木,然后绕过障碍把它交给在东南方的骑士.

题目大意:给出一个矩阵,要求从2号点走到3号点途经至少一个4号点的最少步数

两遍dfs分别求出每个点到2的距离 dis 和到3的距离 dis1 ,然后枚举每一个4号点,则途径该4号点的最短路径则为 dis+dis1 ,挑一个最小的即可

代码如下:

#include<cstring>
#include<ctype.h>
#include<cstdio>
#include<queue>
#define N 1005
using namespace std;
inline int read(){
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') f=-1; c=getchar();}
    while(isdigit(c)) x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
bool b[N][N];
int n,m,top,xx,yy,ans=2147483647;
int a[N][N],dis[N][N],dis1[N][N];
int fx[5]={0,1,0,-1,0};
int fy[5]={0,0,-1,0,1};
struct State{
    int x,y,step;
    State(int _=0,int __=0,int ___=0):x(_),y(__),step(___){}
};
struct Point{
    int x,y;
    Point(int _=0,int __=0):x(_),y(__){}
}Knight,Pri,s[N*N];
typedef Point Grass;
queue<State> q;
inline bool limit(int x,int y){
    if(x<=0 || x>n || y<=0 || y>m) return false;
    return true;
}
void Floodfill(Point x,int dis[N][N]){
    while(!q.empty())q.pop();
    memset(b,false,sizeof b);
    q.push(State(x.x,x.y,0));
    b[x.x][x.y]=true;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]==1) b[i][j]=true;
    while(!q.empty()){
        State x=q.front();q.pop();
        for(int i=1;i<=4;i++){
            xx=x.x+fx[i];yy=x.y+fy[i];
            if(b[xx][yy] || !limit(xx,yy)) continue;
            b[xx][yy]=true;dis[xx][yy]=x.step+1;
            q.push(State(xx,yy,x.step+1));
        }
    }
}
int main(){
    m=read();n=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            a[i][j]=read();
            if(a[i][j]==1) b[i][j]=true;
            if(a[i][j]==2) Pri=Point(i,j);
            if(a[i][j]==3) Knight=Point(i,j);
            if(a[i][j]==4) s[++top]=Grass(i,j);
        }
    Floodfill(Pri,dis);//求出每个点到2号点的距离
    Floodfill(Knight,dis1);//求出每个点到3号点的距离
    for(int i=1;i<=top;i++){
        if(dis[s[i].x][s[i].y] && dis1[s[i].x][s[i].y])
        ans=min(ans,dis[s[i].x][s[i].y]+dis1[s[i].x][s[i].y]);//挑最小的
    }
    printf("%d",ans);
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值