The Shortest Path in Nya Graph HDU - 4725 最短路,SPFA算法+优先队列,网络层加虚拟点

时间:2019-09-22
本文章向大家介绍The Shortest Path in Nya Graph HDU - 4725 最短路,SPFA算法+优先队列,网络层加虚拟点,主要包括The Shortest Path in Nya Graph HDU - 4725 最短路,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.

InputThe 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.OutputFor 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

题意:给定一幅有层次的线路图,第一行输入 N,M,C 表示 N 个点和 M条边,每两层之间通过的费用是 C
意思就是,除了走给定的路之外,我们还可以选择穿透层次,花费 C 的费用走到上一层或者下一层的任意一个节点,而不去走题目给定的边。
然后第二行 N个数就是表示第 i 个节点的层号,然后 M 行是描述边的。

思路:由于数据太大,一次可以设想每层都有一个入口和出口,层内的点到出口的距离为0,同样入口也是,层与层之间通过
让每层只出不进的出口连接上下两层只进不出的入口,权值是c,层内点与点之间的初始距离为无穷,有额外边的为额外值。
这样有N个初始的点,外加N个入口和N个出口,总共有3*N个点,边的数量也要变大。我将第N+1到2*N的点设为出口,将2*N+1到3*N之间的点
设为入口,具体内容见代码。

代码:
  1 #include <cstdio>
  2 #include <fstream>
  3 #include <algorithm>
  4 #include <cmath>
  5 #include <deque>
  6 #include <vector>
  7 #include <queue>
  8 #include <string>
  9 #include <cstring>
 10 #include <map>
 11 #include <stack>
 12 #include <set>
 13 #include <sstream>
 14 #include <iostream>
 15 #define mod 998244353
 16 #define eps 1e-6
 17 #define ll long long
 18 #define INF 0x3f3f3f3f
 19 using namespace std;
 20 
 21 //数据开到比n*3要大
 22 const int maxn = 1000005;
 23 //结构体定义边的信息
 24 struct node1 
 25 {
 26     int y,z,next;
 27 };
 28 node1 no[maxn];
 29 //结构体定义为优先结构
 30 struct node2
 31 {
 32     //x表示当前点,len表示从起点到x的权值
 33     int x,len;
 34     friend bool operator < (node2 a,node2 b)
 35     {
 36         return a.len>b.len;
 37     }
 38 };
 39 //t表示测试样例数,n表示点数,m表示额外边数,p表示层与层之间的权值
 40 int t,n,m,p;
 41 //存放边的位置
 42 int head[maxn];
 43 //存放起点到其他点的最短距离
 44 int dis[maxn];
 45 //标记是否为最短点
 46 bool vis[maxn];
 47 //表示边的数量
 48 int s;
 49 //函数用于储存边的信息
 50 //表示从x到y的权值为z
 51 void add(int x,int y,int z)
 52 {
 53     no[s].y=y;
 54     no[s].z=z;
 55     no[s].next=head[x];
 56     head[x]=s++;
 57 }
 58 //初始化层与层之间入口与出口的连接
 59 //a表示层数,b表示层之间的权值
 60 void init(int a,int b)
 61 {
 62     add(a+1,2*n+2,b);
 63     for(int i=2;i<n;i++)
 64     {
 65         add(n+i,2*n+i-1,b);
 66         add(n+i,2*n+i+1,b);
 67     }
 68     add(2*n,3*n-1,b);
 69 }
 70 //函数求最短路
 71 void spfa()
 72 {
 73     //定义优先队列
 74     priority_queue<node2> qu;
 75     node2 q;
 76     //初始化数据
 77     memset(vis,0,sizeof(vis));
 78     memset(dis,INF,sizeof(dis));
 79     dis[1]=0;
 80     q.x=1;
 81     q.len=0;
 82     //起点为1,权值为0
 83     qu.push(q);
 84     while(!qu.empty())
 85     {
 86         q=qu.top();
 87         qu.pop();
 88         //如果当前点已找过,则无需再找
 89         if(vis[q.x])
 90         {
 91             continue;
 92         }
 93         //标记此点已找过
 94         vis[q.x]=1;
 95         //遍历此点连接的边
 96         for(int i=head[q.x];i!=-1;i=no[i].next)
 97         {
 98             int u=no[i].y;
 99             int v=no[i].z;
100             //更新起点到u的最小值
101             if(dis[u]>dis[q.x]+v)
102             {
103                 dis[u]=dis[q.x]+v;
104                 //将此点入队
105                 node2 s;
106                 s.x=u;
107                 s.len=dis[u];
108                 qu.push(s);
109             }
110         }
111     }
112 }
113 int main()
114 {
115     scanf("%d",&t);
116     //ans表示测试的第几个样例
117     int ans=1;
118     while(t--)
119     {
120         s=1;
121         memset(head,-1,sizeof(head));
122         scanf("%d %d %d",&n,&m,&p);
123         //初始化层
124         init(n,p);
125         int a,b,c;
126         //初始化点与层之间的权值
127         for(int i=1;i<=n;i++)
128         {
129             scanf("%d",&a);
130             add(i,a+n,0);
131             add(a+2*n,i,0);
132         }
133         //初始化点与点之间的权值
134         for(int i=1;i<=m;i++)
135         {
136             scanf("%d %d %d",&a,&b,&c);
137             add(a,b,c);
138             add(b,a,c);
139         }
140         spfa();
141         printf("Case #%d: ",ans++);
142         //判断是否有解
143         if(dis[n]!=INF)
144         {
145             printf("%d\n",dis[n]);
146         }
147         else
148         {
149             printf("-1\n");
150         }
151     }
152 }


原文地址:https://www.cnblogs.com/mzchuan/p/11567580.html