【解题思路】
首先建模。题目要求的是换乘次数的最小值,因此尝试把边和换乘的概念联系在一起。该题中的巴士是“单程巴士”,因此该图是有向无权图。该问题中的“最短路径”指的是有向无权图中的最短路径,即两点之间路径上边的条数。以巴士站为顶点,如果两顶点之间有边,说明两巴士站之间有直达的巴士线路。
如果两顶点之间最短路径长度为1,那么换乘次数是0。
如果两顶点之间最短路径长度为2,那么换乘次数是1。
…
如果两顶点之间最短路径长度为x,那么换乘次数是x-1。
输入时,一条线路上任何两顶点之间都要从前面的顶点向后面的顶点连一条有向边。
解法1:广搜
- 使用广搜可以求无权图上的最短路径问题,复杂度不超过为O(V^2)。
- 用广搜求顶点1到顶点n的最短路径
- 如果存在,则输出最短路径长度减1
- 如果不存在,输出NO
解法2:把无权图当做带权图,求最短路径
对于无权图,可以将该图每条边的权值都视为1,而后就可以使用Floyd,Dijkstra,SPFA等方法求解。
【注意】由于每行末尾可能是"\r\n",因此在输入第一行m与n后,需要去掉本行的换行符时,不能只写一句cin.get()(或getchar()),因为当结尾是"\r\n"时,只会读入"\r",还留下了"\n"。
这里可以使用getline(cin, s)读入整行一直读完本行的’\n’。
#include <bits/stdc++.h>
using namespace std;
int f[505][505];
int n,m,t;
int main()
{
memset(f,0x3f,sizeof(f));
string s;
cin>>m>>n;
for(int i=1;i<=n;i++) f[i][i]=1;//注意:初始化为1 代表乘车次数
for(int i=1;i<=m+1;i++){
getline(cin,s);
vector<int> v;
int ls=s.size();
t=0;
for(int j=0;j<ls;j++){
if(s[j]>='0'&&s[j]<='9')t=t*10+s[j]-'0';
else if(s[j]==' '){
if(t>0) v.push_back(t);
t=0;
}
}
if(t>0) v.push_back(t);
ls=v.size();
for(int j=0;j<ls-1;j++)
for(int k=j+1;k<ls;k++) f[v[j]][v[k]]=1;//注意:顺序
v.clear();
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
if(f[1][n]>=10000)cout<<"NO";
else cout<<f[1][n]-1;//注意:乘车次数减一
return 0;
}