题目链接
题意
给定n节点,节点之间有道路相连,但是每个节点都有个开关,只有开关指向的节点才能通行,你可以搬动开关。给定起点终点,求最少搬动开关次数。
解法
建图,对于每个节点,初始开关对准的节点连边,权值为0,代表经过这个边不需要动开关。对于其他链接的节点连边,权值为1,代表经过这个边需要动开关。跑一遍起点到终点最短路,dis数组求出来的就是最少搬动开关次数。
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
#include<cstdio>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
using namespace std;
typedef long long ll;
const int maxn=550;
const int maxe=5050;
const int inf=0x3f3f3f3f;
struct Edge{
int v,w,next;
}edge[maxe];
int head[maxn],cnt;
bool vis[maxn];
int in[maxn];
int dis[maxn];
int n,m;
void init(){
memset(head,-1,sizeof(head));
cnt=0;
}
void add(int u,int v,int w){
edge[cnt].v=v;
edge[cnt].next=head[u];
edge[cnt].w=w;
head[u]=cnt;
cnt++;
}
bool spfa(int s) {
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
memset(dis,0x3f,sizeof(dis));
queue<int>q;
q.push(s);
vis[s]=true;
in[s]++;
dis[s]=0;
while(q.size()) {
int p=q.front();q.pop();
vis[p]=false;
for(int i=head[p];i!=-1;i=edge[i].next) { //SPFA
int v=edge[i].v;
if(dis[v]>edge[i].w+dis[p]) {
dis[v]=edge[i].w+dis[p];
in[v]++;
if(in[v]>=n)
return true;//这个点更新了多于n次,说明存在负环
if(!vis[v]) {
vis[v]=true;
q.push(v);
}
}
}
}
return false;
}
int main(){
IOS
init();
int s,t;
cin>>n>>s>>t;
for(int i=1;i<=n;i++){
int tmp,v;
cin>>tmp;
if(!tmp)
continue;
tmp--;
cin>>v;
add(i,v,0);
while(tmp--){
cin>>v;
add(i,v,1);
}
}
spfa(s);
if(dis[t]!=inf)
cout<<dis[t]<<endl;
else
cout<<"-1"<<endl;
}