题意:
这是带层的点,从本层的点到上下一层的任何一个节点的权值为c,也有一些点与点之间的路径。主要是建图,建图结束跑一下dijkstra就可以了。
思路:
我们主要说一下建图。
我们可以把每个点的层数看成是一个节点从N+1开始标记。对于这个层数节点 我们对每个在这个层的点 建一条从层数节点出发到这个层的点权值为0有向边。
然后对每个点到他的上、下一层建一条权值为c的有向边。
最后再对m对点建边即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=5*1e5+10;
const int inf=0x3f3f3f3f;
int head[maxn];
int vis[maxn];
int dis[maxn];
int layer[maxn];
int vislay[maxn];
int cnt;
struct edge {
int u,v,w,next;
}e[maxn];
struct qnode{
int dist,num;
friend bool operator < (qnode a, qnode b){
return a.dist >b.dist;
}
};
void init(){
memset(vis,0,sizeof(vis));
memset(dis,inf,sizeof(dis));
memset(head,-1,sizeof(head));
memset(vislay,0,sizeof(vislay));
}
void add_edge(int u,int v,int w){
e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt;
}
int dijkstra(int b,int n){
priority_queue<qnode>q;
vis[b]=1;
dis[b]=0;
qnode now,temp;
now.dist=dis[b];
now.num=b;
q.push(now);
while(!q.empty()){
now=q.top();
q.pop();
vis[now.num]=0;
for(int i=head[now.num];i!=-1;i=e[i].next){
if(dis[e[i].v]>dis[now.num]+e[i].w){
dis[e[i].v]=dis[now.num]+e[i].w;
if(!vis[e[i].v]){
temp.dist=dis[e[i].v];
temp.num=e[i].v;
q.push(temp);
vis[vis[e[i].v]]=1;
}
}
}
}
return dis[n];
}
int main()
{
int t,tt=0,n,m,c;
scanf ("%d",&t);
while(t--){
cnt = 0;
init();
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=n;i++){
scanf("%d",&layer[i]);
vislay[layer[i]]=1; //标记一下这个层数有没有点
}
for(int i=1;i<=n;i++){
add_edge(layer[i]+n,i,0); //自己的层数节点到自己建一条权值为0的边。
if(layer[i]-1>0&&vislay[layer[i]-1]){
add_edge(i,layer[i]+n-1,c); //这个点可以到的下面建一条权值为c的边
}
if(layer[i]+1<=n&&vislay[layer[i]+1]){
add_edge(i,layer[i]+n+1,c); //这个点可以到的上面建一条权值为c的边
}
}
for(int i=1;i<=m;i++){
int uu,vv,ww;
scanf("%d%d%d",&uu,&vv,&ww);
add_edge(uu,vv,ww);
add_edge(vv,uu,ww);
}
printf("Case #%d: ",++tt);
int ans=dijkstra(1,n);
if(ans==inf){
printf("-1\n");
}
else{
printf("%d\n",ans);
}
}
return 0;
}