A1131 Subway Map (30分)

Posted tsruixi

tags:

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

一、技术总结

  1. 题目意思是,给定N条地铁线,然后可能线路与线路之间会有转换站,给出,出发点和目的点,要求输出乘坐的站数以及在每条线路上的转换点,包括出发点和目的点。具体可以查看例子。
  2. 我们使用vector用来存储地图,unordered_map<int, int>类型的line来进行存储站点与站点之间所属的线路(就是几号线的意思),因为站点编号为4位,所以采用编号idx10000+id,然后后一个使用线路编号。
  3. 采用dfs深度搜索的办法,如果是当node==end1,同时可能出现乘坐站点数量cnt比之前少或则站点数量一样,但是转换线路较少(这里使用transferCnt函数来判断),那么就更新数据。最后node==end1,return。遍历过程中,从第一个结点开始,遍历它能够到达的结点,如果visit为0,代表该结点没有被访问过,然后进入置为1,将该结点插入tempPath路径中。然后dfs递归,传参时结点数量加一,记得要重新将该结点置为0,然后将该结点弹出路径,因为在其他路径中可能会使用到该结点。
  4. transferCnt函数,该函数作用就是用来计算已经生成的路径中换线路的次数。这时line变量就发挥作用了,初始化线路数量cnt = -1, preLine = 0代表当前线路的编号,然后从第二个结点开始遍历。初始化cnt=-1,是因为开始为了获取第一条线路的编号,之后如果有与第一条线路不同,代表转线一次,仔细理解一下。
  5. 最后就是输出结果了,首先打印乘坐站点的数量,直接输出minCnt问题不大;然后是输出线路的问题,这里其实跟transferCnt函数的思想是一致的,首先初始化preLine=0,即不知道线路,要先去获取线路,pretransfer=start,这是为第一条线路的输出做准备。也是从第二个结点开始遍历,如果发现线路不同,同时还要判断一下是否preLine=0,因为第一次线路的改变是为了获取真实线路,没有意义。只有当第二次出现preLine不同时,代表真正意义上的转线,需要进行输出结果,同时更新preLine为新线路的编号,也要将pretransfer赋值为转换站点的编号,作为下一条线路的开始站点。
  6. 要慢慢去理解,这一题一位我将=敲成了==导致出现段错误,看了一晚上,也不知道问题在哪,还是要小心啊,不过这也算是积累经验。

二、参考代码

#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 分)

1131 Subway Map(30 分)

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

PAT甲级1131 Subway Map (30分)(DFS)

PAT甲级1131 Subway Map (30分)(DFS)

PAT1131Subway Map (30)