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的主要内容,如果未能解决你的问题,请参考以下文章