题意:
给定路线数m
,站点数n
,m
条单程路线会经过哪些站点,问从起点1到终点n最少要换乘几次**。
思路:
换乘多少次 可以转换为 乘坐过多少次车减1
步骤:
-
1、在同一条路线中,任意一个 在此路线上的车站 均能 沿着该路线的方向 到达后面的车站,权值都是
1
,表示 只乘坐一次车。 -
- 解释:以样例
4 7 3 6
为例,分别将4 ~ 7、4 ~ 3、4 ~ 6、7 ~ 3、7 ~ 6、3 ~ 6
连一条边,权值为1
:表示从 车站4
做到 车站7
只要乘一次车,表示从 车站4
做到 车站3
只要乘一次车等等…
- 解释:以样例
-
2、不是同一线路上 或者 在同一路线上但是不符合上面一条 的车站 相互之间的权值赋为
0
,表示 两个节点之间不连通。 -
3、通过建图,由于权值均是
1
,我们使用最常规的bfs就行了,求出1
号点到n
号点最少乘过多少次车(当然用其他的最短路算法也是可以的,只不过要由数据范围来确定选择哪一种) -
4、由换乘次数 = 乘车次数 - 1,最后
dist[n]-1
(代码之中为t.step-1
,是一样的)即为所求。(初始时dist
数组均置为inf
,当然-1
也是可以的)
注意:
这道题的输入,一条路线经过若干站点,但是站点个数不给,所以可以考虑用 stringstream
处理读入
初始用cin
输入m、n
两个变量后如果想用getline
读取一整行,在此之前还应当用getline
吃掉输入m、n
后产生的回车符。(代码中有体现)
建图的时候,就像我们上面分析的一样,不一定非要建成真正的路线图,要根据实际问题进行抽象。
时间复杂度:
O(M∗N^2)
瓶颈在于main
函数中的建图过程,而不是bfs
假设1
条路线经过所有的站,则边数为(N−1)+(N−2)+…+1=N∗(N−1)/2
题目共有M
条,因此运行的最多次数是M∗N∗(N−1)/2
因此时间复杂度是 O(M∗N^2)
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int m, n;
const int N = 510;
int g[N][N];
int stop[N];
int dist[N];//记录步数
struct node
{
int num, step;//编号、步数
};
queue<node> q;
void bfs()
{
while(!q.empty())
{
node t = q.front();
q.pop();
if(t.num == n){//到达了终点,将答案输出
cout<<t.step-1<<endl;
return ;
}
for(int i=1; i<=n; ++i)
{
if(g[t.num][i]&&dist[i]==inf){//如果边权为1且没有被走过我们就走过去,只要两个判断就行
q.push({i, t.step+1});
dist[i] = t.step+1;
}
}
}
cout<<"NO"<<endl;
return ;
}
int main()
{
cin>>m>>n;
string line ;
getline(cin, line);// 一定要先过滤掉回车
for(int i=0;i<m;++i)
{
getline(cin, line);
stringstream ssin(line);
int cnt = 0, p;
while(ssin>>p) stop[cnt++] = p;
for(int j=0; j<cnt; ++j){
for(int k=j+1; k<cnt; ++k){
g[stop[j]][stop[k]] = 1;
}
}
}
memset(dist, 0x3f, sizeof dist);//初始化为0x3f3f3f3f或-1,都可以
dist[1] = 0;
q.push({1, 0});
bfs();
return 0;
}