POJ1847 Tram SPFA算法变形

原题地址:http://poj.org/problem?id=1847

Tram:有轨电车

这题就是构造一个有向无权图,然后每一个点都会有一个开关,这个开关指向他的其中一个出度。当途经这个点的时候,如果要从开关指向的边离开,则没事,如果不从开关指向的边离开,那么就要下车把开关掰到要离开的那条边上去。注意,离开之后那个开关是不会“弹”回去的。这跟现实铁路中的道岔还挺像。

这里我们用邻接表+SPFA来实现。注意是没有边权的。然后加了个switched数组,switched[i]表示第i个点开关指向的边的编号。在松弛代码中,我们会用到这个玩意儿。SPFA算法的队列使用STL的队列(手打队列麻烦)

注意最后不连通的判断,因为图是没有负权的(因为你最低也就是0,不可能走一圈下来掰了-1次开关吧),所以不用判断点是否入队超N次。不连通说明肯定没有搜到终点,终点的d数组肯定也没有被更新,所以就 判断是否为INF(0x3f3f3f3f)就能判断是否连通。

代码:

//Accepted
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
queue<int>q;
struct Edge
{
	int v,next;
}a[10010];
int n,m=0,src,dest,tmp,tmp2,link[1010],d[1010],switched[1010];
bool visit[1010];
void addedge(int s,int d)
{
	m++;
	a[m].v=d;
	a[m].next=link[s];
	link[s]=m;
}
void spfa()
{
	q.push(src);
	d[src]=0;
	visit[src]=true;
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		visit[x]=0;
		for(int i=link[x];i!=0;i=a[i].next)
		{
			if(d[x]+(switched[x]==a[i].v?0:1)<d[a[i].v])
			{
				d[a[i].v]=d[x]+(switched[x]==a[i].v?0:1);
				if(visit[a[i].v]==false)
				{
					visit[a[i].v]=true;
					q.push(a[i].v);
				}
				
			}
		}
	}
}
int main()
{
	memset(d,0x3f,sizeof(d));
	scanf("%d%d%d",&n,&src,&dest);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&tmp);
		for(int j=1;j<=tmp;j++)
		{
			scanf("%d",&tmp2);
			if(j==1)switched[i]=tmp2;
			addedge(i,tmp2);
		}
	}
	spfa();
	if(d[dest]==0x3f3f3f3f)printf("-1
");
	else
	printf("%d
",d[dest]);
	return 0;
}
原文地址:https://www.cnblogs.com/oier/p/5560711.html