PAT A 1131 Subway Map(30分)

一、题目概述

依据给定地铁路线图,找到源点、汇点间经过站数最少的路线,若两条路线经过站数相同,选择需换乘数少者。

二、思路

1、关于如何判断a-b两站间的路线是几号地铁线路:
开辟一个10000 * 10000单元的数组是不现实的,空间效率很低。因此采用边界散列的思维,站点最大10000,则a * 10000 + b和b * 10000 + a可以唯一标识a-b间的路径。因此a-b所在的地铁线路号存储在line[ a * 10000 + b]和line[b * 10000 + a]中。

2、求解最短路径
方案是多样的:
(1)利用BFS按层访问的性质,找到所有经过结点数相同的源点、汇点间的路径,再对路径dfs选择出换乘最少的路径。
(2)dijkstra算法求最短路径,在对路径dfs选择换乘最少的路径。
(3)dfs遍历所有到达汇点的路径,比较路径上的结点数、换乘数,选择路径。

出于代码量的考虑,选择方案3。

三、代码

#include <cstdio>
#include <vector>
#include <unordered_map>
using namespace std;
vector<int> G[10000], path, a, visited(1e4, 0);
unordered_map<int, int> line;
int N, K, Min;
void dfs(int v, int d)
{
    visited[v] = 1;
    a.push_back(v);
    if(v == d)
    {
        int cnt = 0;
        for(int i = 1; i < a.size() - 1; ++i)
            if(line[a[i - 1] * 1e4 + a[i]] != line[a[i] * 1e4 + a[i + 1]])
                ++cnt;
        if(!path.size() || a.size() < path.size() || (a.size() == path.size() && cnt < Min))
        {
            path = a;
            Min = cnt;
        }
    }
    else for(int i = 0; i < G[v].size(); ++i)
        if(!visited[G[v][i]] && (!path.size() || (path.size() && a.size() < path.size())))
            dfs(G[v][i], d);
    visited[v] = 0;
    a.pop_back();
}
int main()
{
    scanf("%d", &N);
    for(int i = 1, M, pre, v; i <= N; ++i)
    {
        scanf("%d %d", &M, &pre);
        for(int j = 1; j < M; ++j)
        {
            scanf("%d", &v);
            G[pre].push_back(v);
            G[v].push_back(pre);
            line[pre * 1e4 + v] = line[v * 1e4 + pre] = i;
            pre = v;
        }
    }
    scanf("%d", &K);
    for(int i = 0, s, d; i < K; ++i)
    {
        scanf("%d %d", &s, &d);
        path.clear();
        dfs(s, d);
        printf("%d\n", path.size() - 1);
        for(int j = 1, pre = path[0]; j < path.size(); ++j)
            if(j + 1 == path.size() || line[path[j - 1] * 1e4 + path[j]] != line[path[j] * 1e4 + path[j + 1]])
            {
                printf("Take Line#%d from %04d to %04d.\n", line[path[j - 1] * 1e4 + path[j]], pre, path[j]);
                pre = path[j];
            }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值