A1131 Subway Map (30分)
Posted tsruixi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了A1131 Subway Map (30分)相关的知识,希望对你有一定的参考价值。
一、技术总结
- 题目意思是,给定N条地铁线,然后可能线路与线路之间会有转换站,给出,出发点和目的点,要求输出乘坐的站数以及在每条线路上的转换点,包括出发点和目的点。具体可以查看例子。
- 我们使用vector用来存储地图,unordered_map<int, int>类型的line来进行存储站点与站点之间所属的线路(就是几号线的意思),因为站点编号为4位,所以采用编号idx10000+id,然后后一个使用线路编号。
- 采用dfs深度搜索的办法,如果是当node==end1,同时可能出现乘坐站点数量cnt比之前少或则站点数量一样,但是转换线路较少(这里使用transferCnt函数来判断),那么就更新数据。最后node==end1,return。遍历过程中,从第一个结点开始,遍历它能够到达的结点,如果visit为0,代表该结点没有被访问过,然后进入置为1,将该结点插入tempPath路径中。然后dfs递归,传参时结点数量加一,记得要重新将该结点置为0,然后将该结点弹出路径,因为在其他路径中可能会使用到该结点。
- transferCnt函数,该函数作用就是用来计算已经生成的路径中换线路的次数。这时line变量就发挥作用了,初始化线路数量cnt = -1, preLine = 0代表当前线路的编号,然后从第二个结点开始遍历。初始化cnt=-1,是因为开始为了获取第一条线路的编号,之后如果有与第一条线路不同,代表转线一次,仔细理解一下。
- 最后就是输出结果了,首先打印乘坐站点的数量,直接输出minCnt问题不大;然后是输出线路的问题,这里其实跟transferCnt函数的思想是一致的,首先初始化preLine=0,即不知道线路,要先去获取线路,pretransfer=start,这是为第一条线路的输出做准备。也是从第二个结点开始遍历,如果发现线路不同,同时还要判断一下是否preLine=0,因为第一次线路的改变是为了获取真实线路,没有意义。只有当第二次出现preLine不同时,代表真正意义上的转线,需要进行输出结果,同时更新preLine为新线路的编号,也要将pretransfer赋值为转换站点的编号,作为下一条线路的开始站点。
- 要慢慢去理解,这一题一位我将=敲成了==导致出现段错误,看了一晚上,也不知道问题在哪,还是要小心啊,不过这也算是积累经验。
二、参考代码
#include<iostream>
#include<vector>
#include<unordered_map>
using namespace std;
vector<vector<int> > v(10000);
int visit[10000], minCnt, minTransfer, start, endlt;
unordered_map<int, int> line;
vector<int> path, tempPath;
int transferCnt(vector<int> a){
int cnt = -1, preLine = 0;
for(int i = 1; i < a.size(); i++){
if(line[a[i-1]*10000+a[i]] != preLine) cnt++;
preLine = line[a[i-1]*10000+a[i]];
}
return cnt;
}
void dfs(int node, int cnt){
if(node == endlt && (cnt < minCnt || (cnt == minCnt && transferCnt(tempPath) < minTransfer))){
minCnt = cnt;
minTransfer = transferCnt(tempPath);
path = tempPath;
}
if(node == endlt) return;
for(int i = 0; i < v[node].size(); i++){
if(visit[v[node][i]] == 0){
visit[v[node][i]] == 1;
tempPath.push_back(v[node][i]);
dfs(v[node][i], cnt+1);
visit[v[node][i]] = 0;
tempPath.pop_back();
}
}
}
int main(){
int n, m, k, pre, temp;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%d%d", &m, &pre);
for(int j = 1; j < m; j++){
scanf("%d", &temp);
v[pre].push_back(temp);
v[temp].push_back(pre);
line[pre*10000+temp] = line[temp*10000+pre] = i + 1;
pre = temp;
}
}
scanf("%d", &k);
for(int i = 0; i < k; i++){
scanf("%d%d", &start, &endlt);
minCnt = 99999, minTransfer = 99999;
tempPath.clear();
tempPath.push_back(start);
visit[start] = 1;
dfs(start, 0);
visit[start] = 0;
printf("%d
", minCnt);
int preLine = 0, preTransfer = start;
for(int j = 1; j < path.size(); j++){
if(line[path[j-1]*10000+path[j]] != preLine){
if(preLine != 0) printf("Take Line#%d from %04d to %04d.
", preLine, preTransfer, path[j-1]);
preLine = line[path[j-1]*10000+path[j]];
preTransfer = path[j-1];
}
}
printf("Take Line#%d from %04d to %04d.
", preLine, preTransfer, endlt);
}
return 0;
}
以上是关于A1131 Subway Map (30分)的主要内容,如果未能解决你的问题,请参考以下文章
1131 Subway Map (30 分)难度: 难 / Dijkstra最短路
PAT甲级1131 Subway Map (30分)(DFS)