携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情
电车
题目描述
在一个神奇的小镇上有着一个特别的电车网络,它由一些路口和轨道组成,每个路口都连接着若干个轨道,每个轨道都通向一个路口(不排除有的观光轨道转一圈后返回路口的可能)。在每个路口,都有一个开关决定着出去的轨道,每个开关都有一个默认的状态,每辆电车行驶到路口之后,只能从开关所指向的轨道出去,如果电车司机想走另一个轨道,他就必须下车切换开关的状态。
为了行驶向目标地点,电车司机不得不经常下车来切换开关,于是,他们想请你写一个程序,计算一辆从路口 到路口 最少需要下车切换几次开关。
输入格式
第一行有 个整数 (),分别表示路口的数量,和电车的起点,终点。
接下来有 行,每行的开头有一个数字 (),表示这个路口与 条轨道相连,接下来有 个数字表示每条轨道所通向的路口,开关默认指向第一个数字表示的轨道。
输出格式
输出文件只有一个数字,表示从 到 所需的最少的切换开关次数,若无法从 前往 ,输出 。
样例 #1
样例输入 #1
3 2 1
2 2 3
2 3 1
2 1 2
样例输出 #1
0
//双端队列广搜,预计复杂度O(n)
#include<bits/stdc++.h>
using namespace std;
int n,s,t;//s为起点,t为终点
int e[105][105],k[105];//e存边,k表示每个节点出边条数
int dis[105];//距离
inline int read(){
int x=0;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
while(ch<='9'&&ch>='0')x=(x<<3)+(x<<1)+ch-48,ch=getchar();
return x;
}
deque<int> q;//双端队列是一种特别骚的STL,建议学一学,很简单。
bool vis[105];
int main(){
//初始化
memset(vis,0,sizeof(vis));
memset(dis,0x7f,sizeof(dis));
//读入
n=read();s=read();t=read();
for(int i=1;i<=n;i++){
k[i]=read();
for(int j=1;j<=k[i];j++){
e[i][j]=read();
}
}
q.push_back(s);dis[s]=0;
//BFS
while(q.size()){
int x=q.front();q.pop_front();
if(vis[x])continue;//第一次取出就是该点最短路,
//可避免点重复取出(类似DIJIKSTRA)
vis[x]=1;
if(x==t){
printf("%d\n",dis[t]);
return 0;
}
//扫描出边
for(int i=1;i<=k[x];i++){
int y=e[x][i];
if(!k[y])continue;//剪枝:不到没有出边的点
if(i==1){
dis[y]=min(dis[y],dis[x]);
if(!vis[y])q.push_front(y);//因为dis[y]<=dis[x],所以在队列中最小
//从头插入维护队列单调性
}
else{
dis[y]=min(dis[y],dis[x]+1);
if(!vis[y])q.push_back(y);//因为dis[y]在dis[x]“下一层” ,
//从尾插入维护队列单调性
}
}
}
printf("-1");
return 0;
}