PAT甲组1131 Subway Map思路解析和代码

A1131

题目链接

本题思路

本题考查图的遍历,确实不容易啊!!难怪通过率那么低了

  • 输入的数据结构
    • 由于本题数据输入方式(输入一行数据)和其他题目不同(输入一条边的两个顶点来构成图),因此,要通过不断更新前驱,后继的方法存入G[][]中
    • unordered_map line是用hash函数将每条线路的每个站点进行运算,得到不同的hash值作为键key,值value为所属的线路编号。取10000的原因是数据范围在1w以内;hash函数a*10000+b的来历:解决中转站冲突的问题,中转站编号a,但不同线路b不相同,因此得到的hash值保证不会冲突
  • 深度优先搜索寻找合适的路线
    • 参数:now,当前站点编号;lastline,上一站点所属线路编号;E,终点站;step,不同线路条数(等价于中转站个数,用以比较站点相同时取较小的中转站个数)
    • 递归边界:now == E 说明到达终点
    • 递归体:遍历图G,判断是否访问过,与lastline比较后递归
  • 输出问题
    • 与上一站不是同一个线路,输出线路,前驱站点和当前站点,并更新前驱线路和前驱站点
    • 最后输出终点(没有中转站的直接输出起点和终点)

注意:

  • 由于dfs回溯过程中,已经将tempPath和vis[]数组初始化,因此不需要在每次查询之前进行手动初始化
  • 原本仍想使用个人思路中判断是否是中转站的方法来统计路线中的中转站个数,但是一直报错

AC代码

#include 
using namespace std;
const int maxn = 10005;
const int inf = 0x3fffffff;
const int h = 10000;//hash散列运算 
int N;
vector<int> G[maxn];
unordered_map<int, int> line;//标记站点所在线路,对每条线路上的每个站点做hash散列  
bool vis[maxn];

vector<int> tempPath, optPath;
int optStep = inf, optTransCnt = inf;
void dfs(int now, int lastline, int E, int step)
{
	if(now == E)
	{
		tempPath.push_back(now);
		if(tempPath.size() < optStep)
		{
			optStep = tempPath.size();
			optTransCnt = step;
			optPath = tempPath;
		}
		else if(tempPath.size() == optStep && step < optTransCnt)
		{
			optTransCnt = step;
			optPath = tempPath;
		}
		tempPath.pop_back();
		return;
	}
	vis[now] = true;
	tempPath.push_back(now);
	for(int v = 0; v < G[now].size(); ++v)
	{
		int pos = G[now][v];
		if(vis[pos] == false)
		{
			if(line[now * h + pos] != lastline)//与上一站不是同一条线路
				dfs(pos, line[now * h + pos], E, step + 1);
			else
				dfs(pos, lastline, E, step);
		}
	}
	vis[now] = false;
	tempPath.pop_back();
}
int main(int argc, char *argv[]) {
	scanf("%d", &N);
	for(int i = 1; i <= N; ++i)
	{
		//线路上的前驱站点pre,线路起始first,终点last 
		int M, pre, first, last;
		scanf("%d%d", &M, &pre);
		for(int j = 0; j < M - 1; ++j)
		{
			int temp;//线路上的其余站 
			scanf("%d", &temp);	
			G[pre].push_back(temp);
			G[temp].push_back(pre);
			//散列保证中转站所在线路不同,hash值不同 
			line[pre * h + temp] = line[temp * h + pre] = i;
			pre = temp;//更新前驱站点 
		}
	}
	int K;
	scanf("%d", &K);
	while(K--)
	{
		int start, end;
		scanf("%d%d", &start, &end);
	//	memset(vis, false, sizeof(vis)); //每次dfs回溯都会初始化,不需要重复初始化 
	//	tempPath.clear();
		optStep = optTransCnt = inf;
		dfs(start, 0, end, 0);
		printf("%d\n", optPath.size() - 1);//起始站不算 
		int startLine = line[optPath[0] * h + optPath[1]];
		int startPoint = optPath[0];
		for(int i = 1; i < optPath.size() - 1; ++i)
		{
			if(line[optPath[i] * h + optPath[i + 1]] != startLine)
			{
				printf("Take Line#%d from %04d to %04d.\n", startLine, startPoint, optPath[i]);
				startLine = line[optPath[i] * h + optPath[i + 1]];
				startPoint = optPath[i];
			}
		}
		printf("Take Line#%d from %04d to %04d.\n", startLine, startPoint, end);
	}
	return 0;
}

个人思路

一开始乱七八糟的思路

自增计算辨别transfer station
bfs由于会修改结构体中的step,不太适合多次查询,或者每次都初始化step(其实并没有影响step)
记录路径,使用1e4的二维结构体,每次查询清空,会影响效率 用链表存储,顺向还是逆向遍历,因为有两个方向(因为每次都是从一条线路的起始位置开始遍历)
一开始G的存储方式出现问题了(由于本题中,图的输入方式略有不同)

尝试写了bfs,dfs,最后发现自己存储图的方式有严重的问题,当时是用二维vector,每一行是一条线路。太想当然了,压根就不是图的存储方式!!根本算不上有向图无向图乱,存得乱七八糟的

个人错误思路代码

#include 
using namespace std;
const int maxn = 10005;
const int inf = 0x3fffffff;
struct Node{
	int station;//站名 
	int line;//所属线路 
	int step; 
	Node(){}
	Node(int s, int l)
	{
		station = s;
		line = l;
	}
}nodes[maxn];
int N, M, K;
vector<int> G[105];
map<int, int> isTransfer;//自增,访问过两次以上为transfer,loop的话自减 
bool vis[maxn];

vector<int> pre[maxn];//路径前驱结点 
vector<int> tempPath, optPath;
int tempStep, optStep = inf;
int bfs(int S, int E)
{
	queue<Node> q;
	nodes[S].step = 1;
	Node start = nodes[S];
	q.push(start);
	vis[S] = true;
	while(!q.empty())
	{
		Node now = q.front();
		q.pop();
		if(now.station == E)
		{
			return now.step;
		}
		int u = now.line;
		for(int v = 0; v < G[u].size(); ++v)
		{
			int pos = G[u][v];
			if(vis[pos] == true)
				continue;
			nodes[pos].step = now.step + 1;
			Node temp = nodes[pos];
			q.push(temp);
			vis[pos] = true;
		}
	}
}
void dfs(int now, int E, int step)
{
	if(now == E)
	{
		tempPath.push_back(now);
		if(step < optStep)
		{
			optPath = tempPath;
		}
		tempPath.clear();
		return;
	}
	vis[now] = true;
	int u = nodes[now].line;
	for(int v = 0; v < G[u].size(); ++v)
	{
		int pos = G[u][v];
		if(vis[pos] == false)
		{
			dfs(pos, E, step + 1);
		}
	}
	vis[now] = false;
} 
int main(int argc, char *argv[]) {
	scanf("%d", &N);
	for(int i = 1; i <= N; ++i)
	{
		scanf("%d", &M);
		for(int j = 0; j < M; ++j)
		{
			int station;
			scanf("%d", &station);
			nodes[station] = Node(station, i);
			isTransfer[station]++;
			G[i].push_back(station);
		}
		if(G[i][0] == G[i][G[i].size() - 1])//判断是否是loop 
			isTransfer[G[i][0]]--;
	}
	scanf("%d", &K);
	while(K--)
	{
		int start, end;
		scanf("%d%d", &start, &end);
		memset(vis, false, sizeof(vis));
		optPath.clear();
		optStep = inf;
		dfs(start, end, 0); 
		cout << optPath.size() <<endl;
	}
	/*for(map::iterator it = isTransfer.begin(); it != isTransfer.end(); ++it)
	{
		if(it->second >= 2)
		{
			cout << it->first << endl;
		}
	}*/
	return 0;
}

你可能感兴趣的:(PAT,算法,dfs,数据结构,图论)