1131 Subway Map

Posted keep23456

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1131 Subway Map相关的知识,希望对你有一定的参考价值。

题目:https://pintia.cn/problem-sets/994805342720868352/problems/994805347523346432

本文完全参考刘婼的思路和代码!!!

参考地址:https://www.liuchuo.net/archives/3850

  我刚开始想的是用迪杰斯特拉算法得到最短路径,然后对最短路径进行处理,但是我不知道怎么把一个车站和线路对应起来,借此来表示是否是换乘车站,以及求出换乘次数。

  后来看了柳婼的博客,发现其思路真的是太妙了,其代码中使用了unordered_map<int,int> line第一个int存放了两个相邻车站,前四位存储第一个车站,后四位存储第二个车站,使用  line[pre*10000+next] = line[next*10000+pre] = i  来存储,第二个int存放了两个相邻车站的中间线路。于是,有了最短路径和line,可以很容易的求出一条线路的换乘次数以及换乘车站

那么,怎么求一条线路的换乘次数以及换乘车站呢?

写一个函数,其中从头到尾遍历最终保存的路径,preLine为前一小段的线路编号,如果当前的结点和前一个结点 组成的当前线路 和preLine不同,说明有一个换乘,前一个结点是换乘车站,并且换乘次数cnt+1,最后遍历完累加的cnt即是换乘次数

 1 #include<iostream>
 2 #include<vector>
 3 #include<unordered_map>
 4 using namespace std;
 5 
 6 vector<int> adj[10000];//邻接表
 7 int visited[10000],minCnt,minTransfer,start,end1;
 8 unordered_map<int,int> line; //记录相邻两站点的线路
 9 vector<int> path,tempPath;
10 
11 int transferCnt(vector<int> a) { //统计一条线路的中转站个数
12     int cnt = -1,preLine = 0;
13     for(int i = 1; i < a.size(); ++i) {
14         if(line[a[i-1]*10000+a[i]] != preLine) cnt++;
15         preLine = line[a[i-1]*10000+a[i]];
16     }
17     return cnt;
18 }
19 void dfs(int node,int cnt) {
20     if(node == end1 &&(cnt < minCnt || (cnt == minCnt && transferCnt(tempPath) < minTransfer))) {
21         minCnt = cnt;
22         minTransfer = transferCnt(tempPath);
23         path = tempPath;
24     }
25     if(node == end1) return ;
26     for(int i = 0; i < adj[node].size(); ++i)
27         if(visited[adj[node][i]] == 0) {
28             visited[adj[node][i]] = 1;
29             tempPath.push_back(adj[node][i]);
30             dfs(adj[node][i],cnt+1);
31             visited[adj[node][i]] = 0;
32             tempPath.pop_back();
33         }
34 }
35 
36 int main() {
37     int n,m,k,pre,next;
38     cin>>n;
39     for(int i =1; i <= n; ++i) { //一共i条地铁
40         cin>>m>>pre; //第i条地铁,有m个停车站,pre表示前一个停车站
41         for(int j = 1; j < m; ++j) {
42             cin>>next;//下一个停车站
43             adj[pre].push_back(next);
44             adj[next].push_back(pre);
45             line[pre*10000+next] = line[next*10000+pre] = i; //表示相邻站点之间线路的地铁编号,因为是无向图,所以必须双向记录
46             pre = next;
47         }
48     }
49     cin>>k;
50     while(k--) {
51         cin>>start>>end1;
52         minCnt = 99999,minTransfer = 99999;
53         tempPath.clear();
54         tempPath.push_back(start);
55         visited[start] = 1;
56         dfs(start,0);
57         visited[start] = 0;
58         printf("%d
",minCnt);
59         int preLine = 0,preTransfer = start;
60         for(int i = 1; i < path.size(); ++i)
61             if(line[path[i-1]*10000+path[i]] != preLine) {
62                 if(preLine != 0) printf("Take Line#%d from %04d to %04d.
",preLine,preTransfer,path[i-1]); //出现换乘 
63                 preLine = line[path[i-1]*10000+path[i]];
64                 preTransfer = path[i-1];
65             }
66         printf("Take Line#%d from %04d to %04d.
",preLine,preTransfer,end1);
67     }
68     return 0;
69 }

技术图片

总结: 提炼一下这题的要素,方便以后做同类型的题目。

邻接表 :存储整个图。

path :记录一条最短路径(从起点到终点的顶点数最少,且包含的不同类型的边数最少)。

map :记录相邻两个顶点对应一条不同类型的边。

函数:计算path所包含的不同类型(这题是,颜色对应地铁编号)的边数。

而下面这题是一个顶点对应多条不同的边。

以上是关于1131 Subway Map的主要内容,如果未能解决你的问题,请参考以下文章

1131 Subway Map(30 分)

PAT1131Subway Map (30)

1131 Subway Map

1131 Subway Map (30 分)难度: 难 / Dijkstra最短路

PAT A1131 Subway Map

A1131 Subway Map (30分)