原题目参见:1131 Subway Map (30分)不再赘述。
每次查询时,将原图看做一棵以起点为根节点的树,进行层次遍历(使用BFS)。记录下首次由层次遍历经过目的节点的路径深度,遍历到下一层时退出循环。由于是逐层遍历的,初次出现目的节点时的深度就是最短路径长度。
注意一点, 原题目中有一句话:
Each station interval belongs to a unique subway line.
这句话的意思是,2333号站到1204号站之间,只可能有一个线路的车辆通过。也就是说这条线路可以由两个端点唯一表示。由于节点个数为
1
0
5
10^{5}
105级别,如果使用二维数组作为路径标记,空间使用为
4
∗
1
0
10
B
=
40000
M
B
4*10^{10}B=40000MB
4∗1010B=40000MB,超过了内存限制。由于是稀疏图,可以采用map<pair<int,int>, int>
作为索引结构。
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <set>
#include <map>
using namespace std;
const int maxn = 100010;
vector<int> adj[maxn];
vector<vector<int> > paths[maxn];
struct Node {
int level, id;
};
struct interval {
int from, to, line;
bool operator < (const interval& itv) const {
return from != itv.from ? from < itv.from : to < itv.to;
}
};
map<pair<int, int>, int> mp;
void printv3(vector<interval>& v) {
for (auto s : v) {
printf("Take Line#%d from %04d to %04d.\n", s.line, s.from, s.to);
}
}
void compPath(vector<vector<int> >& p) {
vector<interval> vt, bestvt;
int minp=0x7fffffff;
for (auto path : p) {
vt.clear();
interval temp = interval{ path[0], path[1], mp[pair<int,int>(path[0], path[1])] };
for (int i = 0; i < path.size() - 1; i++) {
if (mp[pair<int, int>(path[i], path[i + 1])] == temp.line) {
temp.to = path[i + 1];
}
else {
//要换乘了。
vt.push_back(temp);
temp = interval{ path[i], path[i + 1], mp[pair<int,int>(path[i], path[i+1])] };
}
if (i == path.size() - 2) {
//到终点站了,把最后一站地的路径放进去。
vt.push_back(temp);
}
}
if (bestvt.size()==0) {
bestvt = vt;
minp = path.size() - 1;
}
else {
if (path.size()-1 < minp) {
minp = path.size() - 1;
bestvt = vt;
}
else if (path.size()-1 == minp) {
if (vt.size() < bestvt.size()) {
bestvt = vt;
}
}
}
}
printf("%d\n", minp);
printv3(bestvt);
}
int BFS(int s, int t) {
memset(paths, 0, sizeof(paths));
queue<Node> q;
set<interval> visEdge;
paths[s].push_back(vector<int>(0));
paths[s][0].push_back(s);
q.push(Node{ 0,s });
int tlevel = -1;
while (!q.empty()) {
Node front = q.front();
q.pop();
//所有和最短路径长度相同的路径都访问完毕,退出循环。
if (tlevel!=-1 && front.level >= tlevel)break;
for (auto next : adj[front.id]) {
if (next != front.id && visEdge.count(interval{ front.id, next })==0) {
q.push(Node{ front.level + 1, next });
if (next == t)tlevel = front.level + 1;
for (auto path : paths[front.id]) {
path.push_back(next);
paths[next].push_back(path);
}
visEdge.insert(interval{ front.id, next });
visEdge.insert(interval{ next, front.id });
}
}
}
compPath(paths[t]);
return 0;
}
int main()
{
int n, k, s, t;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &k, &s);
for (int j = 1; j < k; j++) {
scanf("%d", &t);
adj[t].push_back(s);
adj[s].push_back(t);
mp[pair<int, int>(s, t)] = i;
mp[pair<int, int>(t, s)] = i;
s = t;
}
}
scanf("%d", &k);
for (int i = 0; i < k; i++) {
scanf("%d%d", &s, &t);
BFS(s, t);
}
return 0;
}