洛谷P1346 电车
一、题目内容
在一个神奇的小镇上有着一个特别的电车网络,它由一些路口和轨道组成,每个路口都连接着若干个轨道,每个轨道都通向一个路口(不排除有的观光轨道转一圈后返回路口的可能)。在每个路口,都有一个开关决定着出去的轨道,每个开关都有一个默认的状态,每辆电车行驶到路口之后,只能从开关所指向的轨道出去,如果电车司机想走另一个轨道,他就必须下车切换开关的状态。
为了行驶向目标地点,电车司机不得不经常下车来切换开关,于是,他们想请你写一个程序,计算一辆从路口 A 到路口 B 最少需要下车切换几次开关。
输入格式
第一行有 3 个整数 N,A,B(2≤N≤100,1≤A,B≤N),分别表示路口的数量,和电车的起点,终点。
接下来有 N 行,每行的开头有一个数字 Ki(0≤Ki≤N−1),表示这个路口与 Ki 条轨道相连,接下来有 Ki 个数字表示每条轨道所通向的路口,开关默认指向第一个数字表示的轨道。
输出格式
输出文件只有一个数字,表示从 A 到 B 所需的最少的切换开关次数,若无法从 A 前往 B,输出 −1。
输入输出样例
输入 #1
3 2 1
2 2 3
2 3 1
2 1 2
输出 #1
0
二、解题思路
这道题用djikstra也行,用floyd也行。这道题相当于从起点走到终点,求最小总路程。其中对于每个点,如果走到的点是这个点连出的第一条边,总路程不加;如果是其它边,就加一。所以,在建边前,所有边都初始化为正无穷。因为数据不是很大,所以用floyd就行了,我习惯性用我最喜欢的暴力解法(不用怎么动脑)
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=100+10;
const int inf=1e+8;//定义无穷大
int g[maxn][maxn];//地图
int n,m,k,a,b;
int main()
{
cin>>n>>a>>b;//路口数,起点和终点
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
g[i][j]=inf;//初始化地图
g[i][i]=0;//自己踩过的地方不用按开关
}
for(int i=1;i<=n;i++)
{
cin>>k;//每个路口与k条轨道相连
for(int j=1;j<=k;j++)
{
cin>>m;//k个表示每条轨道所通向的路口
if(j==1)//是否是第一条边
g[i][m]=0;
else
g[i][m]=1;//需要按开关
}
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
g[i][j]=min(g[i][j],g[i][k]+g[k][j]);//通过中间点k求得是从i-j近还是从i-k-j近,从而求得a到b的最短路径
if(g[a][b]==inf)//没找到
cout<<"-1";
else
cout<<g[a][b];
return 0;
}
三、注意事项
这道题是最短路问题,dijksra,floyd和spfa都可以解的经典题目。单单那floyd来说,这道题首先要找到核心算法g[i][j]=min(g[i][j],g[i][k]+g[k][j])
,然后想好建图方式和判断方法。还有一个我们要注意的是我们建的每一条边都只是单向边,不要用g[i][j]=g[j][i]
。
蒟蒻写得很烂而且有参考一些大佬的讲解,说的不好的地方请批评指正。