ACM最短路--The Shortest Path in Nya Graph --SPFA

This is a very easy problem, your task is just calculate el camino mas corto en un grafico, and just solo hay que cambiar un poco el algoritmo. If you do not understand a word of this paragraph, just move on.
The Nya graph is an undirected graph with “layers”. Each node in the graph belongs to a layer, there are N nodes in total.
You can move from any node in layer x to any node in layer x + 1, with cost C, since the roads are bi-directional, moving from layer x + 1 to layer x is also allowed with the same cost.
Besides, there are M extra edges, each connecting a pair of node u and v, with cost w.
Help us calculate the shortest path from node 1 to node N.

Input
The first line has a number T (T <= 20) , indicating the number of test cases.
For each test case, first line has three numbers N, M (0 <= N, M <= 10 5) and C(1 <= C <= 10 3), which is the number of nodes, the number of extra edges and cost of moving between adjacent layers.
The second line has N numbers l i (1 <= l i <= N), which is the layer of i th node belong to.
Then come N lines each with 3 numbers, u, v (1 <= u, v < =N, u <> v) and w (1 <= w <= 10 4), which means there is an extra edge, connecting a pair of node u and v, with cost w.
Output
For test case X, output "Case #X: " first, then output the minimum cost moving from node 1 to node N.
If there are no solutions, output -1.
Sample Input

2
3 3 3
1 3 2
1 2 1
2 3 1
1 3 3

3 3 3
1 3 2
1 2 2
2 3 2
1 3 4

Sample Output

Case #1: 2
Case #2: 3

题目大意:
有多个层面,每个层面有一些带编号的点,编号在1–N,首先告诉你每一点在哪个平面,然后又告诉你每个点之间的距离,这是一个双向路径图,另外这些点可能在同一个平面,也可能在不同平面,如果在不同平面,并且两个平面编号差距为1,也就是X平面到X+1平面,这些点就可以直接通过两个相邻平面相互到达,距离为固定的C,如果某两个平面的点之间就存在路径,也可以通过平面相互到达,就需要判断最小的距离,现在问你从1出发到n最短路径多少?
注意一个坑点:在同一个平面上的点彼此的距离不为0,也存在路径关系才能判断是否能到达。

解题思路:
没有负环存在,省了很多麻烦,因为点数目比较多,就直接通过链接表建立图,再spfa处理一下就得到结果了,那么如何建图呢,首先根据两平面的点可以相互到达这个性质,我们首先需要建立一个点与平面链接的关系,那么我们就将一个平面定义成一个点,编号n+x,相当于如果这些点都在这个平面上,那么可以认为这些点到点n+x距离为0,然后相邻平面之间,也就是相邻的平面点n+x到n+x+1之间距离为C,同样也是双向路径,双向建图。

注意建图还有一个坑点,建图分点与平面建图,平面与平面建图,点与点之间建图,这里必须强调存在一个关系,就是先平面与平面建图,再点与平面建图,再点与点,因为这是一个生成先后关系,可以理论认为有了平面才可以在平面上加入点与点,不然结果会错误。

另外建图还有一个问题就是点到包含它的平面,不能同时建立点到平面为0和平面到这个点为0的关系,因为这样的话,就会导致平面上所有的点彼此距离都为0,虽然意义上点到平面和平面到点距离都为0,但为了避免这种运算时的错误,得处理一下,写成平面到点的距离为0,点到平面的距离为无穷,但是点到包含它的平面的两个相邻平面距离为C,也就是直接建立这个点到相邻平面单向路径的关系。这样在实际意义上就可以满足我们的需要,而不会产生上述问题。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<queue>
#include<stack>
#include<string.h>
using namespace std;
const int N=200000;
struct Node{
	int v,w,next;
}edge[4*N];
int head[N],cnt;
void add_edge(int u,int v,int w)
{
	edge[cnt].v=v;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	head[u]=cnt++;	
} 
bool vis[N];
int dis[N];
queue<int>q;
int n,m,c;
void spfa()
{
	while(!q.empty())
	q.pop();
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=2*n;i++)
	dis[i]=1e9;
	dis[1]=0;
	vis[1]=true;
	q.push(1);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=head[u];i!=-1;i=edge[i].next)
		{
			int v=edge[i].v;
			int w=edge[i].w;
			if(dis[v]>dis[u]+w)
			{
				dis[v]=dis[u]+w;
				if(!vis[v])
				{
					vis[v]=true;
					q.push(v);
				}
			}
		}
	}
	if(dis[n]==1e9)cout<<"-1\n";
	else cout<<dis[n]<<endl;
}
int indx[N];
int main()
{
	int t,cas=0;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d",&n,&m,&c);
		memset(head,-1,sizeof(head));
		memset(vis,0,sizeof(vis));
		memset(indx,0,sizeof(indx));
		cnt=0;
		for(int i=1;i<=n;i++)
		{
			int x;
			scanf("%d",&x);
			indx[i]=x;
			vis[x]=true;
		}
		//先建立平面与平面关系
		for(int i=1;i<n;i++)
		if(vis[i]&&vis[i+1])
		{
			add_edge(n+i,n+i+1,c);
			add_edge(n+i+1,n+i,c);
		}
		//再建立平面到点的关系
        for(int i = 1; i <= n; i++) 
        {
        	//点到包含它的平面距离为0
            add_edge(n+indx[i],i,0);
            //点到包含它的平面的相邻平面距离为C
            if(indx[i] > 1)
                add_edge(i,n+indx[i]-1,c);
            if(indx[i] < n)
                add_edge(i,n+indx[i]+1,c);
        }
        //最后建立点与点数据关系
		while(m--)
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			add_edge(x,y,z);
			add_edge(y,x,z);
		}
		printf("Case #%d: ",++cas);
		spfa();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值