[ACM] hdu Find a way


Find a way

                                                               Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                                                  Total Submission(s): 3238    Accepted Submission(s): 1051


Problem Description
Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki.
Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city. So yifenfei made arrangements with Merceki to meet at a KFC. There are many KFC in Ningbo, they want to choose one that let the total time to it be most smallest. 
Now give you a Ningbo map, Both yifenfei and Merceki can move up, down ,left, right to the adjacent road by cost 11 minutes.
 

Input
The input contains multiple test cases.
Each test case include, first two integers n, m. (2<=n,m<=200). 
Next n lines, each line included m character.
‘Y’ express yifenfei initial position.
‘M’    express Merceki initial position.
‘#’ forbid road;
‘.’ Road.
‘@’ KCF
 

Output
For each test case output the minimum total time that both yifenfei and Merceki to arrival one of KFC.You may sure there is always have a KFC that can let them meet.
 

Sample Input
4 4 Y.#@ .... .#.. @..M 4 4 Y.#@ .... .#.. @#.M 5 5 Y..@. .#... .#... @..M. #...#
 

Sample Output
66 88 66
 

Author
yifenfei
 

Source


解题思路:这道题属于简单的入门级bfs,由于昨天被某一bfs题虐了半天,这道题做起来感觉很好,写下来一气呵成,bfs框架也差不多印在脑子里了。题目两个人到KFC见面,两个人在不同的位置,KFC也不只一个,对每个人BFS广搜,求出每个人到各个KFC的最短距离,最后对于多个KFC地点,求出两个人到这的最小步数的和,取最小值就可以了。

代码:(该代码错误!虽然能提交通过,但是代码是错的!下面已经改正,并附上了正确代码)

#include <iostream>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;

char map[202][202];//地图
int a[202][202];//保存第一个人Y到各个节点(坐标)的最小步数,有的节点不用访问,下面有说明
int b[202][202];//保存第二个人M 
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};//方向
int n,m;//地图大小
int kcount;//KFC一共的个数
int yx,yy,mx,my;//Y的坐标,M的坐标
int flag;//用来判断执行第一个人的BFS还是第二个人的BFS

void getmap()//输入地图
{
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
    {
        cin>>map[i][j];
        if(map[i][j]=='@')
            kcount++;
        else if(map[i][j]=='Y')
        {
            yx=i;
            yy=j;
        }
        else if(map[i][j]=='M')
        {
            mx=i;
            my=j;
        }
    }
}

struct node
{
    int x,y;
};

void bfs(int x,int y)
{
    int k=0;//搜索过程中的KFC的个数,初始为0
    queue<node>q;
    node aa,bb;
    aa.x=x;
    aa.y=y;
    if(!flag)//flag=0的时候执行Y的bfs
        a[x][y]=0;
    else
        b[x][y]=0;//flag=1的时候执行M的bfs
    q.push(aa);
    while(!q.empty())
    {
        bb=q.front();
        q.pop();
        if(k==kcount)
            break;//退出条件 ,当搜索过程中访问过的KFC数量等于整个地图总的KFC数量时就可以退出,剩下的节点不需要再访问
        for(int i=0;i<4;i++)
        {
            aa.x=bb.x+dx[i];
            aa.y=bb.y+dy[i];
           if(!flag)//Y的bfs
           {
                if(aa.x>=0&&aa.x<n&&aa.y>=0&&aa.y<m&&a[aa.x][aa.y]==0&&map[aa.x][bb.y]!='#')
                {
                    if(map[aa.x][aa.y]=='@')//搜索过程中遇到KFC,数量加1
                        k++;
                    a[aa.x][aa.y]=a[bb.x][bb.y]+1;
                    q.push(aa);
                }
           }
           else//M的bfs
           {
            if(aa.x>=0&&aa.x<n&&aa.y>=0&&aa.y<m&&b[aa.x][aa.y]==0&&map[aa.x][bb.y]!='#')
            {
                if(map[aa.x][aa.y]=='@')
                    k++;
                b[aa.x][aa.y]=b[bb.x][bb.y]+1;
                q.push(aa);
            }
           }
        }//for
    }//while
}
int main()
{
    while(cin>>n>>m)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        kcount=0;
        flag=0;
        getmap();
        bfs(yx,yy);
        flag=1;
        bfs(mx,my);
        int minn=1000000;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
        {
            if(map[i][j]=='@')
            {
                minn=min(minn,a[i][j]+b[i][j]);//某个KFC地点两者到达的总步数之和,取最小值。
            }
        }
        cout<<minn*11<<endl;
    }
    return 0;
}


运行截图:



2014.3.3  修改

最近又重新做这个题,发现上面写的代码虽然能通过,但是错误的!  

if(aa.x>=0&&aa.x<n&&aa.y>=0&&aa.y<m&&a[aa.x][aa.y]==0&&map[aa.x][bb.y]!='#')

map[aa.x][bb.y]这里应该是map[aa.x][aa.y]才对,当时不知道为什么会写成那样,而且能通过,更不得其解,但是后来改回来以后,提交竟然通不过了!为这个问题困扰了两天!下午,让老师帮我看看。后来老师出了一个神测试数据。

4 5
@  .  # @ .
  .   .  Y #  .
@ # M #  .
@  .  .  # @      这个测试数据用我改后的代码竟然输出为0,后来用别人的其他能在航电上通过的代码测试,输出也是0,但该测试数据结果应该为77才对。这就说明了该题后台测试数据不全面。

后来想了想为什么会输出为0,该测试数据很特殊,因为第四列@和第五列的@在广搜时搜不到!因为被墙#完全隔着,其步数永远是0,后来在遍历全图,取两人在@处最小步数时,肯定是没有搜到的@处最小,因为二者到此处的步数均为0,想加也为0,所以必须得加一个限制条件,取@处二者步数相加和的最小且该@处必须已经被搜过!加上这一句,代码就没问题了。我把上面提到的错误(map[aa.x][bb.y]这里应该是map[aa.x][aa.y]才对)改了以后,又在后面加上了限制条件,再重新提交,Ac了!哎,不容易啊,一桩心事终于了了!

下面附上修改后并优化后的代码:

#include <iostream>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;

char map[202][202];//地图
int a[202][202];//保存第一个人Y到各个节点(坐标)的最小步数,有的节点不用访问,下面有说明
int b[202][202];//保存第二个人M
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};//方向
int n,m;//地图大小
int yx,yy,mx,my;//Y的坐标,M的坐标

void getmap()//输入地图
{
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
    {
        cin>>map[i][j];
        if(map[i][j]=='Y')
        {
            yx=i;
            yy=j;
        }
        else if(map[i][j]=='M')
        {
            mx=i;
            my=j;
        }
    }
}

struct node
{
    int x,y;
};

void bfs(int x,int y,int num[202][202])//广搜
{
    queue<node>q;
    node aa,bb;
    aa.x=x;
    aa.y=y;
    num[x][y]=0;
    q.push(aa);
    while(!q.empty())
    {
        bb=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            aa.x=bb.x+dx[i];
            aa.y=bb.y+dy[i];
            if(aa.x>=0&&aa.x<n&&aa.y>=0&&aa.y<m&&num[aa.x][aa.y]==0&&map[aa.x][aa.y]!='#')
            {
                num[aa.x][aa.y]=num[bb.x][bb.y]+1;
                q.push(aa);
            }
        }//for
    }//while
}
int main()
{
    while(cin>>n>>m)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        getmap();
        bfs(yx,yy,a);
        bfs(mx,my,b);
        int minn=1000000;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
        {
            if(map[i][j]=='@'&&b[i][j]!=0)//必须保证此处@被访问过!写成a[i][j]!=0也可以
            {
                minn=min(minn,a[i][j]+b[i][j]);//某个KFC地点两者到达的总步数之和,取最小值。
            }
        }
        cout<<minn*11<<endl;
    }
    return 0;
}




posted @ 2014-01-18 14:57  同学少年  阅读(191)  评论(0编辑  收藏  举报