两次BFS(UVA 11624,hdoj 2612)

题目:UVA 11624 Fire!(用的洛谷)
阿伟今天在刷kuangbin大佬的题时,有一道需要用两次BFS的题,由于是海外OJ,因此也没提交上去,不过思想掌握了是最重要的。
题目大意: Joe被困在迷宫,迷宫里有火源,Joe和火源每分钟都可以移动一个单位,并且火源在这一分钟内可以向上下左右四个方向传播(如果没有墙的话),求出Joe能否逃出迷宫(走到边缘就算逃出成功),如果可以逃出,输出最短时间,如果不可以,输出“IMPOSSIBLE”。
(注意:不只有一个火源!!!)
题解: 此题由于Joe的路径并不会改变火的传播,而火的传播会改变Joe的路径,因此选择用两次BFS来完成。一次BFS是将火传播到每个地方的时间用BFS写出来,然后再次用BFS将Joe的路线找出。在开始的时候time数组初始化为无穷大,当其中元素为无穷大时,说明这个地方火到达不到。在存地图的时候,由于可能有多个火源,于是要每次读取的时候判断一下是不是“F”,如果是的话,入队。在Joe的BFS中,check时,要比较Joe到达所在的位置与火传播到这个位置所需要的时间,如果Joe比火先到达该位置,说明该位置是可行的。
上代码(不确定是否正确,交到UVA上老说编译错误,嘤嘤嘤~)

#include 
#include 
#include 
using namespace std;
char maps[1001][1001];
int vis[1001][1001];
int time[1001][1001];
int dir[4][2]=
{
    {1,0},
    {-1,0},
    {0,1},
    {0,-1},
};
int sx,sy,r,c;
struct node
{
    int x;
    int y;
    int time;
};
queue<node>q;
bool check_fire(int x,int y)
{
    if(x<0||y<0||x>=c||y>=r)
        return false;
    else
    if(maps[x][y]=='#'||vis[x][y])
        return false;
    return true;
}
bool check_Joe(int x,int y,int times)
{
    if(x<0||y<0||x>=r||y>=c)
        return false;
    else
    if(maps[x][y]=='#'||vis[x][y]||times>=time[x][y])
        return false;
    return true;
}
void bfs_fire()
{
    node next;
    while(!q.empty())
    {
        node tmp=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            next=tmp;
            next.x+=dir[i][0];
            next.y+=dir[i][1];
            if(check_fire(next.x,next.y))
            {
                next.time++;
                vis[next.x][next.y]=1;
                time[next.x][next.y]=next.time;
                q.push(next);
            }
        }
    }
}
int bfs_Joe()
{
    node start,next;
    start.x=sx;
    start.y=sy;
    start.time=0;
    q.push(start);
    vis[sx][sy]=1;
    while(!q.empty())
    {
        node tmp=q.front();
        q.pop();
        if(tmp.x==0||tmp.y==0||tmp.x==r-1||tmp.y==c-1)
            return tmp.time+1;
        for(int i=0;i<4;i++)
        {
            next=tmp;
            next.x+=dir[i][0];
            next.y+=dir[i][1];
            next.time++;
            if(check_Joe(next.x,next.y,next.time))
            {
                vis[next.x][next.y]=1;
                q.push(next);
            }
        }
    }
    return -1;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        while(!q.empty())
            q.pop();
        cin>>r>>c;
        memset(maps,0,sizeof(maps));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<r;i++)
        {
            for(int j=0;j<c;j++)
            {
                cin>>maps[i][j];
                if(maps[i][j]=='F')
                {
                    node tmp;
                    tmp.x=i;
                    tmp.y=j;
                    tmp.time=0;
                    time[i][j]=0;
                    vis[i][j]=1;
                    q.push(tmp);
                }
                else
                    if(maps[i][j]=='J')
                {
                    sx=i;
                    sy=j;
                }
            }
        }
        for(int i=0;i<1001;i++)
        {
            for(int j=0;j<1001;j++)
                time[i][j]=1e9+7;
        }
        bfs_fire();
        memset(vis,0,sizeof(vis));
        int ans=bfs_Joe();
        if(ans==-1)
            cout<<"IMPOSSIBLE"<<endl;
        else
            cout<<ans<<endl;
    }
}

题目:hdoj 2612 Find a way
这题也是阿伟自己出的呦~
题目大意: 有两个人Y和M要去KFC见面,但城市里有很多KFC,他们想找一个用时最短的KFC,注意:用时是两个人的总时间,并不是两个人用时最长的那个。
题解: 看到这个题,我首先想到的是对每个KFC用BFS搜,但是看了大佬的题解之后,说那个方法会超时,因为不知道有多少KFC,有可能会有很多,然而这样就会超时。于是我就想对Y和M两个人用BFS,这样找出这两个人到达每个KFC所用的时间,然后找出总时间最少的那个就可以了。在这里我用了三维数组,因为对两个人用BFS是完全相同的,用三维数组避免了写两次BFS。
AC代码:

#include 
#include 
#include 
using namespace std;
char maps[201][201];
int kfc[201][201];//记录两人到达某个KFC的总时间
int vis[2][201][201];//用三维数组避免写两次bfs
int n,m,yx,yy,mx,my;
int mins=1e9+7;//记录两人到达某KFC的最短时间
struct node
{
    int x;
    int y;
    int time;
};
int dir[4][2]=
{
    {1,0},
    {-1,0},
    {0,1},
    {0,-1},
};
bool check(int x,int y,int k)
{
    if(x<0||y<0||x>=n||y>=m)
        return false;
    else
        if(maps[x][y]=='#'||vis[k][x][y])
            return false;
    return true;
}
void bfs()
{
    queue<node>q;
    node start,next;
    for(int k=0;k<2;k++)
    {
        if(k==0)
        {
            start.x=yx;
            start.y=yy;
        }
        else
        {
            start.x=mx;
            start.y=my;
        }
        start.time=0;
        q.push(start);
        vis[k][start.x][start.y]=1;
        while(!q.empty())
        {
            node tmp=q.front();
            q.pop();
            for(int i=0;i<4;i++)
            {
                next=tmp;
                next.x+=dir[i][0];
                next.y+=dir[i][1];
                if(check(next.x,next.y,k))
                {
                    next.time++;
                    if(maps[next.x][next.y]=='@')
                    {
                        kfc[next.x][next.y]+=next.time;
                        if(kfc[next.x][next.y]<mins&&k==1)//在这里判断大小的话,只能是在第二个人之后,因此要加上k==1这个判别条件
                            mins=kfc[next.x][next.y];//在这里判断就不用再在下面排序找最小值了
                    }
                    vis[k][next.x][next.y]=1;
                    q.push(next);
                }
            }
        }
    }
}
int main()
{
    while(cin>>n>>m)
    {
        mins=1e9+7;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                cin>>maps[i][j];
                if(maps[i][j]=='Y')
                {
                    yx=i;
                    yy=j;
                }
                else
                    if(maps[i][j]=='M')
                {
                    mx=i;
                    my=j;
                }
            }
        }
        memset(kfc,0,sizeof(kfc));
        memset(vis,0,sizeof(vis));
        bfs();
        cout<<mins*11<<endl;
    }
}

你可能感兴趣的:(两次BFS(UVA 11624,hdoj 2612))