POJ - 1847 Tram 最短路,思维建图

题目链接

POJ-1847

题意

给定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;
	} 
	

猜你喜欢

转载自blog.csdn.net/TheSunspot/article/details/107739760