Borg Maze(POJ3026)

大致的题意:

一个 Y 行  X 列的迷宫,空格表示可通行的路, “#”表示墙 ,不能通行,现在从S出发,要求用最短的路径连接所有的字母A,输出这条路径的长度。

思路:

首先是要构图,但难点在于必须要计算每个字母与字母之间的最短距离,而且图每一个格的长度是1,那么两点的距离就是横坐标之差加上纵坐标之差,

计算两个字母的最短距离可以用BFS(广搜)或DFS(深搜),两个字母的最短距离就是两个字母构成边的权值;

根据题目的意思,走过的重复的路是不会再计算的,所以可以用到 Prim 或 Kruskal 算法来计算。

需要注意的是: 输入的时候一定要去除空格,应为这个问题,WA十几次快哭了

以下是 BFS + PRIM 的做法:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int INF = 100000;
int n , m ,num;//num :表示有多少个字母
int dir[4][2] = {-1 , 0 , 1 , 0 , 0 ,1 , 0 , -1};
int edge[200][200];//图的邻接矩阵
int vis[200][200];//用来记录字母是否被访问过
int lowcost[200];
int post[200][200];//记录是第几个字母。用于构图
char map[55][55];
struct node
{
    int x , y;
    int dist;
};
void BFS(node s)//求两字母的最短距离
{
    memset(vis ,0 ,sizeof(vis));
    int i;
    node t, tmp;   
    queue<node> q;   
    q.push(s);
    vis[s.x][s.y] = 1;
    while(!q.empty())
    {
        t = q.front();
        q.pop();
        for(i = 0 ; i < 4; i++)
        {
             tmp.x  = t.x + dir[i][0];
             tmp.y  = t.y + dir[i][1];
             tmp.dist = t.dist+1;
            if(tmp.x >=0  && tmp.y < n && tmp.x < m && tmp.y >=0 )
            {
                if(!vis[tmp.x][tmp.y] && map[tmp.x][tmp.y] != '#')
                {
                    vis[tmp.x][tmp.y] = 1;
                    int x = post[tmp.x][tmp.y];
                    int y = post[s.x][s.y];
                   
                    if(map[tmp.x][tmp.y] == 'A' || map[tmp.x][tmp.y] == 'S')
                    {
                      edge[x][y] =edge[y][x] = tmp.dist;
                      // cout << x << " "<< y <<endl;
                   }
                    q.push(tmp);
                }
            }
        }
    }
    return;
}
void PRIM()
{
    int i , j , sum = 0;
    int visp[200];
    for(i = 1 ; i <= num ; i++)
    {
        lowcost[i] = edge[1][i];
        visp[i] = 0;
    }
    visp[1] = 1;
    for(i = 2 ; i <= num ;i++)
    {
        int min = INF  , u = -1;
        for(j = 1 ; j <= num ; j++)
        {
            if(!visp[j] && lowcost[j] < min)
            {
                min = lowcost[j];
                u = j;
            }
        }
        if(u == -1)
            continue;
        visp[u] =1;
        sum += min;
        for(j = 1 ; j <= num ; j++)
        {
            if(!visp[j] && lowcost[j] > edge[u][j])
            {
                lowcost[j] = edge[u][j];
            }
        }
    }
    printf("%d\n" ,sum);
}
int main()
{
    int t;
   // freopen("in.txt" ,"r" ,stdin);
   // freopen("out.txt" ,"w", stdout);
    scanf("%d" ,&t);
    while(t--)
    {
        num = 1;
        scanf("%d%d" ,&n ,&m);
        char c;
        c =getchar();//在这里被坑了好多次。
        while(c ==' ')
            c = getchar();
        int i, j ;
        memset(post ,0 ,sizeof(post));
        memset(edge , 0 ,sizeof(edge));
        for(i = 0 ; i < m ; i++)
        {
            gets(map[i]);
            for(j = 0 ;j < n ; j++)
            {
                if(map[i][j] == 'S')
                	post[i][j] = 1;
                else if( map[i][j] == 'A' )
                     post[i][j] = ++num;
            }
        }
        for(i = 0 ; i < m ; i++)
        {
            for(j = 0 ; j < n ;j++)
            {
                if(post[i][j] > 0)//大于0的都是字母,计算用这个字母做起点,计算它与其他字母的最短距离。
                {
                    node tmp;
                    tmp.x = i;
                    tmp.y = j;
                    tmp.dist = 0;
                    BFS(tmp);
                }
            }
        }
        PRIM();
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值