L3-014 周遊世界 bfs
周遊世界是件浪漫事,但規劃旅行路線就不一定了…… 全世界有成千上萬條航線、鐵路線、大巴線,令人眼花繚亂。所以旅行社會選擇部分運輸公司組成聯盟,每家公司提供一條線路,然後幫助客戶規劃由聯盟內企業支援的旅行路線。本題就要求你幫旅行社實現一個自動規劃路線的程式,使得對任何給定的起點和終點,可以找出最順暢的路線。所謂“最順暢”,首先是指中途經停站最少;如果經停站一樣多,則取需要換乘線路次數最少的路線。
輸入格式:
輸入在第一行給出一個正整數N(≤),即聯盟公司的數量。接下來有N行,第i行(,)描述了第i家公司所提供的線路。格式為:
M S[1] S[2] ⋯ S[M]
其中M(≤)是經停站的數量,S[i](,)是經停站的編號(由4位0-9的數字組成)。這裡假設每條線路都是簡單的一條可以雙向執行的鏈路,並且輸入保證是按照正確的經停順序給出的 —— 也就是說,任意一對相鄰的S[i]和S[i+1](,)之間都不存在其他經停站點。我們稱相鄰站點之間的線路為一個運營區間,每個運營區間只承包給一家公司。環線是有可能存在的,但不會不經停任何中間站點就從出發地回到出發地。當然,不同公司的線路是可能在某些站點有交叉的,這些站點就是客戶的換乘點,我們假設任意換乘點涉及的不同公司的線路都不超過5條。
在描述了聯盟線路之後,題目將給出一個正整數K(≤),隨後K行,每行給出一位客戶的需求,即始發地的編號和目的地的編號,中間以一空格分隔。
輸出格式:
處理每一位客戶的需求。如果沒有現成的線路可以使其到達目的地,就在一行中輸出“Sorry, no line is available.”;如果目的地可達,則首先在一行中輸出最順暢路線的經停站數量(始發地和目的地不包括在內),然後按下列格式給出旅行路線:
Go by the line of company #X1 from S1 to S2.
Go by the line of company #X2 from S2 to S3.
......
其中Xi是線路承包公司的編號,Si是經停站的編號。但必須只輸出始發地、換乘點和目的地,不能輸出中間的經停站。題目保證滿足要求的路線是唯一的。
輸入樣例:
4
7 1001 3212 1003 1204 1005 1306 7797
9 9988 2333 1204 2006 2005 2004 2003 2302 2001
13 3011 3812 3013 3001 1306 3003 2333 3066 3212 3008 2302 3010 3011
4 6666 8432 4011 1306
4
3011 3013
6666 2001
2004 3001
2222 6666
輸出樣例:
2
Go by the line of company #3 from 3011 to 3013.
10
Go by the line of company #4 from 6666 to 1306.
Go by the line of company #3 from 1306 to 2302.
Go by the line of company #2 from 2302 to 2001.
6
Go by the line of company #2 from 2004 to 1204.
Go by the line of company #1 from 1204 to 1306.
Go by the line of company #3 from 1306 to 3001.
Sorry, no line is available.
找了幾篇非dfs的部落格,都有點問題,只保證了最短路徑沒保證最少換乘,不過資料較弱也都給過了。dfs暴力過的不明白時間複雜度怎麼算的,我造了幾組資料給我tle了。
要以bfs來做的話,正常以點作為bfs節點來跑會出現多路徑問題,不能保證最短路是最少換乘,所以應該以邊作為bfs節點,即可同時保證最短路和最少換乘。網上有的給的是dijkstra,其實沒必要,直接bfs就好。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
struct Graph {int v, i;};
struct Edge {int u, v, t;};
struct Node {int s, c, p;};
struct Path {int i, t;};
vector<Graph>g[N];
vector<Edge>e;
vector<Node>d;
vector<Path>path;
int bfs(int st, int ed) {
for (int i = 0; i < e.size(); i++) d[i] = {(int)1e9, (int)1e9, -1};
path.clear();
int mn = 1e9, ret = 1e9;
queue<int>q;
for (auto p:g[st]) {
d[p.i] = {1, 0, -1};
q.push(p.i);
}
while (!q.empty()) {
int u = q.front(); q.pop();
if (d[u].s > ret) break;
if (e[u].v == ed) {
ret = d[u].s;
if (d[u].c < mn) {
mn = d[u].c;
path.clear();
path.push_back({ed, e[u].t});
int r = u, l = d[r].p;
while (l != -1) {
if (e[l].t != e[r].t) {
path.push_back({e[l].v, e[l].t});
}
r = l, l = d[r].p;
}
reverse(path.begin(), path.end());
}
}
for (auto p:g[e[u].v]) {
int v = p.i;
if (d[v].s > d[u].s + 1) {
d[v].s = d[u].s + 1;
d[v].c = d[u].c + (e[u].t != e[v].t);
d[v].p = u;
q.push(v);
} else if (d[v].s == d[u].s + 1) {
if (d[v].c > d[u].c + (e[u].t != e[v].t)) {
d[v].c = d[u].c + (e[u].t != e[v].t);
d[v].p = u;
}
}
}
}
return (ret == 1e9 ? -1 : ret);
}
signed main() {
ios::sync_with_stdio(false);
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
int k, u, v;
cin >> k >> u;
while (k-- > 1) {
cin >> v;
e.push_back({u, v, i});
d.push_back({0, 0, 0});
g[u].push_back({v, (int)e.size() - 1});
e.push_back({v, u, i});
d.push_back({0, 0, 0});
g[v].push_back({u, (int)e.size() - 1});
u = v;
}
}
int k;
cin >> k;
while (k--) {
int s, e;
cin >> s >> e;
int ans;
if ((ans = bfs(s, e)) == -1) cout << "Sorry, no line is available." << '\n';
else {
cout << ans << '\n';
for (int i = 0, p = s; i < path.size(); i++) {
cout << "Go by the line of company #" << path[i].t << " from ";
cout << setw(4) << setfill('0') << p;
cout << " to ";
cout << setw(4) << setfill('0') << path[i].i;
cout << "." << '\n';
p = path[i].i;
}
}
}
return 0;
}