我认为,这道题的难点在于路径输出
我一开始的思路,是对每一个站点记录ta在哪一条地铁线上
这样就会带来一个问题:换乘点要如何处理?
我们换一个思路,从路径出发,记录到达每一个站点时经过了几号线
输出时只要发现这个站点的前后地铁线不同,就认为ta是一个换乘点
每发现一个换乘点,就输出一条路径信息
终点站也可以视为一个换乘点,我们将终点站之后的地铁线设置为0,就可以实现统一的输出了
面对这种最短最优路径问题,我首选dijkstra+dfs的方法,结果TLE了
使用朴素的dijkstra算法会超时:
O
(
n
2
)
=
1000
0
2
=
1
0
8
O(n^2)=10000^2= 10^8
O(n2)=100002=108
需要使用堆优化版本的dijkstra算法:
O
(
m
×
l
o
g
n
)
=
1
0
6
×
l
o
g
10000
=
4
×
1
0
6
O(m×logn)=10^6×log10000=4×10^6
O(m×logn)=106×log10000=4×106
还有没有更简单的方法呢?
因为题目限定,每个换乘点至多有五条线路交汇
这实际上暗示了图的复杂度并不会太高
我们只需要一遍dfs即可
感谢前辈们的赛博指导:
堆优化dijkstra算法
柳神就是我的神!
Tip
- 最短最优路径问题,复杂图使用dijkstra+dfs,简单图使用dfs
- 学会转化问题,从不同角度解决问题
- dfs用于搜索则有回溯,用于遍历则无回溯
TLE代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N = 10010;
const int INF = 0x33333333;
int n, m;
struct node {
int y;
int c;
int nxt;
};
node way[N * 100];
int st[N], tot = -1;
void addway(int u, int v, int w) {
tot++;
way[tot].y = v;
way[tot].c = w;
way[tot].nxt = st[u];
st[u] = tot;
}
int vis[N];
int dis[N];
int dijkstra(int s,int t) {
for (int i = 0; i <= 9999; ++i) {
vis[i] = 0;
dis[i] = INF;
}
dis[s] = 0;
while (1) {
int mn = INF;
int index = -1;
for (int i = 0; i <= 9999; ++i) {
if (!vis[i] && dis[i] < mn) {
mn = dis[i];
index = i;
}
}
if (index == t || index == -1) break;
vis[index] = 1;
for (int i = st[index]; i != -1; i = way[i].nxt) {
dis[way[i].y] = min(dis[way[i].y], dis[index] + 1);
}
}
return dis[t];
}
int station[N];
int line[N];
int ans_station[N];
int ans_line[N];
int ans_cnt;
void dfs(int s,int t,int dis,int cnt,int ans) {
if (dis > ans || (dis == ans && s!=t)) return;
if (dis == ans && s == t) {
if (cnt < ans_cnt) {
ans_cnt = cnt;
for (int i = 1; i <= dis; ++i) {
ans_station[i] = station[i];
ans_line[i] = line[i];
}
}
return;
}
for (int i = st[s]; i != -1; i = way[i].nxt) {
int y = way[i].y;
if (!vis[y]) {
//arrive station through line
station[dis + 1] = y;
line[dis + 1] = way[i].c;
vis[y] = 1;
//different line
if (line[dis+1] != line[dis]) dfs(y, t, dis + 1, cnt + 1, ans);
else dfs(y, t, dis + 1, cnt, ans);
vis[y] = 0;
}
}
}
void prt(int s,int t,int ans) {
//终点也可以视为换乘点
ans_line[ans + 1] = 0;
for (int i = 1; i <= ans; ++i) {
if (ans_line[i] != ans_line[i+1]) {
//ans_station[i]为换乘点
printf("Take Line#%d from %04d to %04d.\n", ans_line[i], s, ans_station[i]);
s = ans_station[i];
}
}
}
int main()
{
for (int i = 0; i <= 9999; ++i) st[i] = -1;
scanf("%d",&n);
for (int i = 1; i <= n; ++i) {
int u, v;
scanf("%d%d", &m, &u);
for (int j = 1; j < m; ++j) {
scanf("%d", &v);
addway(u, v, i);
addway(v, u, i);
u = v;
}
}
scanf("%d", &m);
for (int i = 1; i <= m; ++i) {
int u, v;
scanf("%d%d",&u,&v);
int ans = dijkstra(u, v);
printf("%d\n",ans);
if (ans) {
for (int j = 0; j <= 9999; ++j) vis[j] = 0;
vis[u] = 1;
ans_cnt = INF;
dfs(u, v, 0, 0, ans);
prt(u, v, ans);
}
}
return 0;
}
AC代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N = 10010;
const int INF = 0x33333333;
int n, m;
struct node {
int y;
int c;
int nxt;
};
node way[N * 100];
int st[N], tot = -1;
void addway(int u, int v, int w) {
tot++;
way[tot].y = v;
way[tot].c = w;
way[tot].nxt = st[u];
st[u] = tot;
}
int vis[N];
int station[N];
int line[N];
int ans_station[N];
int ans_line[N];
int ans_cnt;
int ans_dis;
void dfs(int s,int t,int dis,int cnt) {
if (dis > ans_dis) return;
if (s == t && dis <= ans_dis) {
if ((dis < ans_dis) || (dis == ans_dis && cnt < ans_cnt)) {
ans_dis = dis;
ans_cnt = cnt;
for (int i = 1; i <= dis; ++i) {
ans_station[i] = station[i];
ans_line[i] = line[i];
}
}
return;
}
for (int i = st[s]; i != -1; i = way[i].nxt) {
int y = way[i].y;
if (!vis[y]) {
//arrive station through line
station[dis + 1] = y;
line[dis + 1] = way[i].c;
vis[y] = 1;
//different line
if (line[dis+1] != line[dis]) dfs(y, t, dis + 1, cnt + 1);
else dfs(y, t, dis + 1, cnt);
vis[y] = 0;
}
}
}
void prt(int s,int t,int ans) {
//终点也可以视为换乘点
ans_line[ans + 1] = 0;
for (int i = 1; i <= ans; ++i) {
if (ans_line[i] != ans_line[i+1]) {
//ans_station[i]为换乘点
printf("Take Line#%d from %04d to %04d.\n", ans_line[i], s, ans_station[i]);
s = ans_station[i];
}
}
}
int main()
{
for (int i = 0; i <= 9999; ++i) st[i] = -1;
scanf("%d",&n);
for (int i = 1; i <= n; ++i) {
int u, v;
scanf("%d%d", &m, &u);
for (int j = 1; j < m; ++j) {
scanf("%d", &v);
addway(u, v, i);
addway(v, u, i);
u = v;
}
}
scanf("%d", &m);
for (int i = 1; i <= m; ++i) {
int u, v;
scanf("%d%d",&u,&v);
for (int j = 0; j <= 9999; ++j) vis[j] = 0;
vis[u] = 1;
ans_dis = INF;
ans_cnt = INF;
dfs(u, v, 0, 0);
printf("%d\n", ans_dis);
prt(u, v, ans_dis);
}
return 0;
}