poj 3026 Borg Maze(prim+广搜)

1. 题目大意

在一个nrow行ncolumn列的迷宫中,有可行走的通路空格’ ’,不可行走的墙’#’,还有两种英文字母AS,现在从S出发,要求用最短的路径L连接所有字母,输出这条路径L的总长度。一格的长度为1,而且移动的方法只有上、下、左、右,所以在无任何墙的情况下(但#”是必须考虑的,这里只是为了说明)任意两个字母之间的距离就是直接把横坐标之差加上纵坐标之差。注意的是,可行的路为字母和空格不可行的路为 #和矩阵范围之外。

2. 题目分析

根据题意的分离规则,重复走过的路不再计算,因此当使用prim算法求L的长度时,根据算法的特征恰好不用考虑这个问题(源点合并很好地解决了这个问题),L就是最少生成树的总权值W,由于使用prim算法求在最小生成树,因此无论哪个点做起点都是一样的,(通常选取第一个点),因此起点不是S也没有关系,所以所有的AS都可以一视同仁,看成一模一样的顶点就可以了。最后要注意的就是字符的输入cinscanf不读入空字符(包括空格,换行等),gets读入空格,但不读入换行符。剩下的问题关键就是处理任意两字母间的最短距离,由于存在了#”,这个距离不可能单纯地利用坐标加减去计算,必须额外考虑,推荐用BFS(广搜、宽搜),这是本题的唯一难点,因为prim根本直接套用就可以了。

求任意两字母间的最短距离时不能直接用BFS求:

1、必须先把矩阵中每一个允许通行的格看做一个结点(就是在矩阵内所有非#的格都作为图M的一个顶点),对每一个结点i,分别用BFS求出它到其他所有结点的权值(包括其本身,为0),构造结点图M

2、然后再加一个判断条件,从图M中抽取以字母为顶点的图,进而构造字母图N

这个判定条件就是当结点图M中的某点j为字母时,把ij的权值再复制(不是抽离)出来,记录到字母图N的邻接矩阵中;

3、剩下的就是对字母图N求最小生成树了。

3. 代码

#include<stdio.h>

#include<string.h>

#include<queue>

#define MAXN 55

#define MAXINT 999999999

typedef struct myNode

{

      int x;

      int y;

      int step;

}Node;

char map[MAXN][MAXN];

Node node[2*MAXN];

int nrow, ncolumn, nvertex;

int g[2*MAXN][2*MAXN], id[MAXN][MAXN],move[4][2]={{0,1},{0,-1},{-1,0},{1,0}};

 

using namespace std;

 

void init()

{

      int i,j;

      for(i=0;i<2*MAXN;i++)

             for(j=0;j<2*MAXN;j++)

                    (i==j)? (g[i][j]=0) : (g[i][j]=MAXINT);

}

void bfs(Node s)

{

      inti,nx,ny,step;

      intvis[MAXN][MAXN]={{0}};

      Nodetemp,p;

      queue<Node>que;

 

      que.push(s);

      vis[s.x][s.y]=1;

      while(!que.empty())

      {

             temp=que.front();

             que.pop();

             for(i=0;i<4;i++)

             {

                    nx=temp.x+ move[i][0];

                    ny=temp.y+ move[i][1];

                    step=temp.step;

                    if(!vis[nx][ny]&& nx>=0 && nx<ncolumn && ny>=0 &&ny<nrow)

                    {

                           if('A'==map[nx][ny]|| 'S'==map[nx][ny])

                           {

                                  p.x=nx;

                                  p.y=ny;

                                  p.step=++step;

                                  que.push(p);

                                  vis[nx][ny]=1;

                                  g[id[s.x][s.y]][id[nx][ny]]=g[id[nx][ny]][id[s.x][s.y]]=step;

                           }

                           if(''==map[nx][ny])

                           {

                                  p.x=nx;

                                  p.y=ny;

                                  p.step=++step;

                                  que.push(p);

                                  vis[nx][ny]=1;

                           }

                    }

             }

      }

}

void generateGraph()

{

      int i,j;

 

      for(i=0;i<nrow;i++)

             gets(map[i]);

 

      nvertex=0;

      memset(id,0,sizeof(id));

      for(i=0;i<nrow;i++)

      {

             for(j=0;j<ncolumn;j++)

             {

                    if('A'==map[i][j]|| 'S'==map[i][j])

                    {

                           node[nvertex].x=i;

                           node[nvertex].y=j;

                           node[nvertex].step=0;

                           id[i][j]=nvertex++;

                    }

             }

      }

      for(i=0;i<nvertex;i++)

             bfs(node[i]);

}

int prim(int start)

{

   intv,i,distance;

      intvisited[2*MAXN]={0},dis[2*MAXN];

      for(i=0;i<nvertex;i++)

             dis[i]=MAXINT;

   dis[start]=0;

   v=start;

   while(!visited[v])

   {

       visited[v]=1;

       for(i=0;i<nvertex;i++)

       {

           if(!visited[i] && dis[i]>g[v][i])

               dis[i]=g[v][i];

       }

       distance=MAXINT;

       for(i=0;i<nvertex;i++)

       {

           if(!visited[i] && dis[i]<distance)

           {

               distance=dis[i];

               v=i;

           }

       }

   }

      distance=0;

      for(i=0;i<nvertex;i++)

             distance+=dis[i];

      returndistance;

}

int main()

{

      int T;

      char str[100];

      scanf("%d",&T);

      while(T--)

      {

             scanf("%d%d",&ncolumn,&nrow);

             gets(str);

             init();

             generateGraph();

             printf("%d\n",prim(0));

      }

      return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值