Poj 3328的一种解法

来源:互联网 发布:怎样在淘宝上申请店铺 编辑:程序博客网 时间:2024/05/21 04:01

题目描述:http://acm.pku.edu.cn/JudgeOnline/problem?id=3328

今天上午想把3328题做了,一看发现有点难。于是,便上网搜解题报告,最终还是没找到一个解题报告。决定自己把它搞定了。看了discussion,有人说要用优先队列和dij算法或者dfs再或者bfs,但是我没用过优先队列,上午的时间就拿来简单的学学优先队列,再复习一下dij算法。

   下午又把题目读了一遍,发现和我上次做了的那个走迷宫的题极为相似,于是想用和上次一样的方法(BFS)来解决这个问题,不过这次的这个有点特别:有两个出发点要同时考虑,一个左脚,一个右脚;经过仔细思考,发现BFS是可以解决这个题,于是按着自己的想法写了个程序,在贡献了两次WA后换来了一次AC

下面就来讲讲我的解题思路:

根据题意:我们需要注意一下几点(1)逃跑的这个人是从S标记的方格开始走的,进入每个S方格的可以是这个人的左脚,也可以是这个人的右脚(2)只要任何一支脚到达了T标记的方格,就完成一次逃跑,也就是说可以取得一个最小时间了(最优解)(3)用其中的一只脚进入一个方格后,另一支脚可以到达的方格是有限制(这个限制题目说的很清除了)。

解题的大体思路:用一个二维数组保存输入的数据,用一个三维数组保存从出发点到达每个坐标点(也就是每个小方块)所用的最小时间,为什么要用三维的呢?这正是这个题与众不同之处,对于每个坐标点我们要保留两个最小时间:一个是用左脚进入这个坐标点的最小时间,另一个当然就是用右脚进入这个坐标点所用最小时间。 然后就是BFS求到达T标记方块的最小时间。

下面就来看看源程序(程序各个变量的作用都做了详细的解释)

//http://acm.pku.edu.cn/JudgeOnline/problem?id=3328

//BFS

#include <iostream>

#include <string>

#include <queue>

#define INF 1000000

using namespace std;

int w,h; //宽度和高度

int Grid[65][65];//记录每个坐标点的情况,注意一下:例如Grid[2][5],2对应的是竖直向下方向的坐标值

                                                           //5对应的是水平向右方向的坐标值

int d[65][65][2];//记录到的该坐标所需要的最少时间,最低维0下表对应左脚,1下表对应右脚,例如d[3][5][0]的值就是用左脚进入(3,5)点所用的最少时间  d[3][5][1]的值就是用右脚进入(3,5)点所用的最少时间

int Min; //用于保存我需要的那个最少时间                                                                            

void Init(int ww,int hh) //这个函数主要完成数据的读入和数组初始化工作

{

         memset(Grid,0,sizeof(Grid)); //Grid数组的每个元素值初始化为0

         memset(d,12,sizeof(d));//d数组的每个元素初始化一个很大的值,memset函数事实上是对字节的操作,d数组的中的每个元素的每个字节上都赋值为12,这样之后,每个元素的值其实是很大的,不信的话,你可以打印出来看看

         Min=INF;

         w=ww;

         h=hh;

         for(int i=1;i<=h;i++)

                   for(int j=1;j<=w;j++)

                   {

                            char ch;

                            cin>>ch;

                            if(ch>='1'&&ch<='9')

                            Grid[i][j]=ch-'0';

                            else if(ch=='S')

                            Grid[i][j]='S';

                            else if(ch=='T')

                            Grid[i][j]='T';

                            else if(ch=='X')

                            Grid[i][j]='X';

                   }

return ;

}

bool InRectangle(int i,int j) //判断坐标(i,j)是否在宽度和高度的允许范围内

{

         return i>=1&&i<=h&&j>=1&&j<=w;

}

struct Pos //定义一个结构体来保存某一节点的情况

{

         int x,y; //坐标值 ,需要注意一下在这个程序中x保存的是竖直向下为正方向的坐标值,

//y保存是水平向右为正方向的坐标值,这和题目上给出的图表的不一样,其实这都无所谓啦

         int flag; //记录这个坐标点上的数字,或字母

};

void BFS()
{
queue<Pos>que;
Pos p;
for(int j=1;j<=w;j++)
{
   if(Grid[h][j]=='S') //将所有起始点加入到队列中,注意任何一个起始点可以是左脚开始也可以是右脚开始
   {
            p.x=h;
    p.y=j;
    p.flag='S';
    d[h][j][0]=d[h][j][1]=0; //用左脚和用右脚进入起始点,初始化值都为0
    que.push(p);
   }
}
while(!que.empty())
{
   p=que.front();
     que.pop();
   if(p.flag=='T') //检查是否达到了T标记的坐标点,注意左脚、右脚进入的最小值都要检查
   {
    if(d[p.x][p.y][0]<Min) 
       Min=d[p.x][p.y][0];
    if(d[p.x][p.y][1]<Min)
     Min=d[p.x][p.y][1];

   }
      else //下面是两个结构几乎一样的if语句 一个左脚,一个右脚
   { //进入p点时用的是左脚
    if(d[p.x][p.y][0]<INF) //说明p点用左脚到达过
    for(int i=p.x-2;i<=p.x+2;i++)
     for(int j=p.y+1;j<=p.y+3;j++)
     {
      if( InRectangle(i,j)   //(i,j)必须在这个给出的长宽范围内
      && abs(i-p.x)+abs(j-p.y)<=3) //必须满足题目给出的限制条件
      {
       if(1<=Grid[i][j]&&Grid[i][j]<=9 && d[p.x][p.y][0]+Grid[i][j]<d[i][j][1] && d[p.x][p.y][0]+Grid[i][j]<Min)
       {
        Pos newp;
        newp.x=i;
        newp.y=j;
        newp.flag=Grid[i][j];
        que.push(newp); //新的节点进入队列
        d[i][j][1]=d[p.x][p.y][0]+Grid[i][j];//更新用右脚进入(I,j)的最小时间
       }
       else if(Grid[i][j]=='T'&&d[p.x][p.y][0]<d[i][j][1])//&&d[p.x][p.y][0]<Min
       {
                            Pos newp;
        newp.x=i;
        newp.y=j;
        newp.flag=Grid[i][j];
        que.push(newp);
        d[i][j][1]=d[p.x][p.y][0];
       }
      }
     }
  
       //用的是右脚进入p点
    if(d[p.x][p.y][1]<INF) //说明p点用右脚到达过
    for(int i=p.x-2;i<=p.x+2;i++)
     for(int j=p.y-3;j<=p.y-1;j++)
     {
      if( InRectangle(i,j) 
      && abs(i-p.x)+abs(j-p.y)<=3)
      {
       if(1<=Grid[i][j]&&Grid[i][j]<=9 && d[p.x][p.y][1]+Grid[i][j]<d[i][j][0] && d[p.x][p.y][1]+Grid[i][j]<Min)
       {
        Pos newp;
        newp.x=i;
        newp.y=j;
        newp.flag=Grid[i][j];
        //newp.foot=0; //
        que.push(newp);
        d[i][j][0]=d[p.x][p.y][1]+Grid[i][j];
       }
       else if(Grid[i][j]=='T'&&d[p.x][p.y][1]<d[i][j][0])//&&d[p.x][p.y][1]<Min
       {
                            Pos newp;
        newp.x=i;
        newp.y=j;
        newp.flag=Grid[i][j];
        //newp.foot=0; // 左脚
        que.push(newp);
        d[i][j][0]=d[p.x][p.y][1];
       }
      }
     }
   }
}
}
int main()
{
int ww,hh;
while(cin>>ww>>hh)
{
if(ww==0&&hh==0)break;
      Init(ww,hh);
      BFS();
      if(Min!=INF)
          cout<<Min<<endl;
   else cout<<-1<<endl;
}
   return 0;
}