原题链接

考察:最短路+建图

本题最难在建图

根据题意,我们需要在在相邻层(必须都有点存在),额外边之间建边.题目给的N在10^5左右.如果题目给的N只分布在两层,那么暴力建相邻层的边,需要两层for循环判断的时间复杂度在O(n^2).必定TLE.

根据这道题,相邻层的点可以走相邻层的固定路长,也可以走题目给定的m条边.我们可以将层也看作是一个点,如果该层及其相邻层有点分布,我们就建边.这样跑一遍for循环就可以.

但要注意的是,我们不能让同层的点无代价地连接,假设层点为A,相邻层到A需要到A上的点,所以需要一条A到层内点的边.层内点也需要到相邻层外,所以也需要层内点到外层的边.但是这样层内点就连接起来了,与题意不符.因此层点需要分两类,考虑到上面我们说的情况,我们要让层外点连接到层内点,也要让层内点能出去.所以我们建立一个出度点和入度点,这样就解决了问题,最后写一个dijkstra即可

注意:这道题貌似卡SPFA,如果数据量较大,能用dijkstra就用dijkstra

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm> 
 4 #include <queue>
 5 #include <cstdio>
 6 using namespace std;
 7 typedef pair<int,int> pii;
 8 const int N = 6e5+10;
 9 const int M = 3e5+10;
10 int n,m,c,h[M],idx,dist[M];
11 bool islay[M],vis[M];
12 struct Edge{
13     int to,from,next,w;
14 }edge[N];
15 void inits()
16 {
17     fill(h,h+M,-1); idx = 0; 
18     fill(vis,vis+M,0); fill(islay,islay+M,0); 
19 }
20 void add(int a,int b,int c)
21 {
22     edge[idx].w = c,edge[idx].from = a,edge[idx].to = b,edge[idx].next = h[a],h[a] = idx++;
23 }
24 void dijkstra(int st)
25 {
26     memset(dist,0x3f,sizeof dist);
27     dist[st] = 0;
28     priority_queue<pii,vector<pii>,greater<pii> > q;
29     q.push({0,st});
30     while(q.size())
31     {
32         pii it = q.top();
33         int u = it.second;
34         q.pop();
35         if(vis[u]) continue;
36         vis[u] = 1;
37         for(int i=h[u];i!=-1;i=edge[i].next)
38         {
39             int e = edge[i].to;
40             if(dist[e]>dist[u]+edge[i].w)
41             {
42                 dist[e] = dist[u]+edge[i].w;
43                 q.push({dist[e],e});
44             }
45         }
46     }
47 }
48 int main()
49 {
50     //freopen("in.txt","r",stdin);
51     int T,kcase= 0;
52     scanf("%d",&T);
53     while(T--)
54     {
55         inits();
56         scanf("%d%d%d",&n,&m,&c);
57         for(int i=1;i<=n;i++)//直接建边会TLE 
58         {
59             int x;  scanf("%d",&x);//x指第i点所在层 
60             add(i,n+2*x,0);//n+2*x为出度
61             add(n+2*x-1,i,0); 
62             islay[x] = 1;//表示第x层有点,没点的相邻层不能连 
63         }
64         for(int i=1;i<=n;i++)
65         {
66             if(islay[i]&&islay[i+1])
67             {
68                 add(n+2*i,n+2*(i+1)-1,c);
69                 add(n+2*(i+1),n+2*i-1,c);
70             }
71         }
72         while(m--)
73         {
74             int x,y,w; scanf("%d%d%d",&x,&y,&w);
75             add(x,y,w); add(y,x,w);
76         }
77         dijkstra(1);
78         if(dist[n]==0x3f3f3f3f) printf("Case #%d: %d\n",++kcase,-1);
79         else printf("Case #%d: %d\n",++kcase,dist[n]);
80     }
81     return 0;
82 }