要求:n个点m条无向边,每条边都有正权值。每个点都在某一层上,相邻层之间的点移动消耗c。求从第1个点到第n个点的最短距离。0<=n,m<=10^5。
方法:优先队列优化dijkstra 邻接链表
1.这道题如果数据规模小点就是dijkstra裸题了,数据范围大就得优化了。
2.点太多不能用邻接矩阵,只能用邻接链表。
3.点太多需要用优先队列优化的dijkstra。即dijkstra + heap。
注意只需将源点的dis值初始化就行了!!!!不要初始化其他点的dis值!!!
4.标记层优化时间,如果一个层遍历过,则无需再遍历。原理是如果第1层的a点去遍历第2层的c点和d点,那么第1层的b点将不需要遍历第2层的点。因为优先队列的缘故,若要到达第2层的某一点,那么第1层的a点具有比第2层的b点更小的dis值,故用a点遍历后无需用b点遍历。
#include<iostream>
#include<stdio.h>
#include<queue>
#include<vector>
#include<map>
#include<string.h>
#include<math.h>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std ;
int n , m , c ;
int cnt ;
bool vis[100005] ;
bool vis1[100005] ;
int l[100005] ;
int dis[100005] ;
int head[100005] ;
vector <int> lay[100005] ;
struct node
{
int to ;
int val ;
int next ;
}edge[200005] ;
void add(int a , int b , int d)
{
edge[cnt].to = b ;
edge[cnt].val = d ;
edge[cnt].next = head[a] ;
head[a] = cnt ;
cnt ++ ;
}
struct cmp
{
bool operator()(const int &a , const int &b)
{
return dis[a] > dis[b] ;
}
} ;
void dijkstra(int num)
{
int i , j , k ;
int a , b ;
int len , next ;
priority_queue <int , vector<int> , cmp> q ;
while(!q.empty())
q.pop() ;
dis[1] = 0 ;
q.push(1) ;
while(!q.empty())
{
a = q.top() ;
q.pop() ;
if(vis1[a])
continue ;
vis1[a] = 1 ;
for(i = head[a] ; i != -1 ; i = edge[i].next)
{
len = edge[i].val ;
next = edge[i].to ;
if(dis[a] + len < dis[next])
{
dis[next] = dis[a] + len ;
q.push(next) ;
}
}
if(l[a] - 1 >= 1 && !vis[l[a] - 1])
{
vis[l[a] - 1] = 1 ;
for(i = 0 ; i < lay[l[a] - 1].size() ; i ++)
{
next = lay[l[a] - 1][i] ;
if(dis[a] + c < dis[next])
{
dis[next] = dis[a] + c ;
q.push(next) ;
}
}
}
if(l[a] + 1 <= n && !vis[l[a] + 1])
{
vis[l[a] + 1] = 1 ;
for(i = 0 ; i < lay[l[a] + 1].size() ; i ++)
{
next = lay[l[a] + 1][i] ;
if(dis[a] + c < dis[next])
{
dis[next] = dis[a] + c ;
q.push(next) ;
}
}
}
}
printf("Case #%d: " , num) ;
if(dis[n] == inf || n == 0)
printf("-1\n") ;
else
printf("%d\n" , dis[n]) ;
}
int main()
{
int i , j , k ;
int t ;
int u , v , w ;
scanf("%d" , &t) ;
for(j = 1 ; j <= t ; j ++)
{
cnt = 0 ;
memset(vis , 0 , sizeof(vis)) ;
memset(vis1 , 0 , sizeof(vis1)) ;
memset(dis , inf , sizeof(dis)) ;
memset(head , -1 , sizeof(head)) ;
scanf("%d%d%d" , &n , &m , &c) ;
for(i = 1 ; i <= n ; i ++)
scanf("%d" , &l[i]) ;
for(i = 1 ; i <= m ; i ++)
{
scanf("%d%d%d" , &u , &v , &w) ;
add(u , v , w) ;
add(v , u , w) ;
}
for(i = 1 ; i <= n ; i ++)
lay[i].clear() ;
for(i = 1 ; i <= n ; i ++)
lay[l[i]].push_back(i) ;
dijkstra(j) ;
}
}