2021-08-02
09:11:29
链接
https://www.luogu.com.cn/problem/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。
输入输出样例
3 2 1
2 2 3
2 3 1
2 1 2
0
分析:
这是一道图论题,但是我们只看题干的话好像只能找到图中的点,找不到图中的边和权重,题目描述从起点到终点所要做的最少的切换开关的次数。但是每个点(路口)都有不同的状态,这样有点抽象,我们先将样例讲一下
样例建图如下

那么点已经找到了,边和边的权重怎么找呢?
我们看到,每个路口指向的第一个路口为默认状态,就是说,如果你从路口1到路口2的话,如果路口2是路口1的默认状态,那么就不需要切换开关,总切换数没变,就说明该边的权重为0,如果我们从路口1走到路口3的话,但是路口1的默认状态是指向路口2的,那么我们就需要切换一次开关,这使得总切换数+1。所以,我们找到了权重。(边就类似从路口1指向路口2的边)。

所以我们在输入的时候,将所有路口指向的第一个路口设为默认,权值为0,指向其他路口的权值全部为1。
至此,我们已经完全构造好了一个图
样例建图如下

完整代码:
#include<iostream>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=105;
int g[N][N];
int n,from,to;
void Floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(g[i][j]>g[i][k]+g[k][j])
g[i][j]=g[i][k]+g[k][j];
}
}
}
}
int main()
{
cin>>n>>from>>to;
memset(g,0x3f,sizeof g);
for(int i=1;i<=n;i++)g[i][i]=0;
for(int i=1;i<=n;i++)
{
int k;
cin>>k;
for(int j=1;j<=k;j++){
int a;
cin>>a;
if(j==1){
g[i][a]=0;
}
else g[i][a]=1;
}
}
Floyd();
if(g[from][to]==INF)cout<<-1<<endl;
else cout<<g[from][to]<<endl;
return 0;
}
2021-08-02
09:41:36
浙公网安备 33010602011771号