建完图直接套个Dijkstra+priority的模板就好了,建图一小时,套模板半分钟。
//这题主要难在建图上,要将层抽象出来成为n个点(对应编号依次为n+1~n+n),
//然后层与层建边,点与点建边,层与在该层上的点建边(边长为0),点与相邻层建边(边长为c)。
//ps:这样处理就不用拆点了。不过要注意的是相邻两层必须都要有点才建边(不然会WA,可以参考我贴的数据)。
//然后还有一点要注意的,就是题目隐含条件:同层如没有边是无法直接到达的
//同层的两个点,必须有一个点到达相邻一层,然后再返回本层,曲线救国
//这就要求我们在建立点和边的关系的时候用一个小技巧
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxe=4000100;
const int maxv=200010;
int cnt;
int dis[maxv],head[maxv];
bool visit[maxv];
struct Edge{
int to,val,next;
}edge[maxe];
struct Node{
int u,dis;
bool operator< (const Node rhs) const{
return this->dis>rhs.dis;
}
}now,temp;
void init(){
memset(head,-1,sizeof head);
memset(dis,INF,sizeof dis);
memset(visit,false,sizeof visit);
cnt=0;
}
void addedge(int from,int to,int val){
edge[cnt].to=to;
edge[cnt].val=val;
edge[cnt].next=head[from];
head[from]=cnt++;
}
void Dijkstra(int s,int head[],Edge edge[],int dist[],bool visit[]) {
int i,v;
dist[s]=0;
priority_queue<Node> pq;
temp.dis=0,temp.u=s;
pq.push(temp);
while(!pq.empty()) {
temp=pq.top();
pq.pop();
if(visit[temp.u]==true)
continue;
visit[temp.u]=true;
for(i=head[temp.u]; i!=-1; i=edge[i].next) {
v=edge[i].to;
if(visit[v]==false&&dist[v]>dist[temp.u]+edge[i].val) {
dist[v]=dist[temp.u]+edge[i].val;
now.u=v;
now.dis=dist[v];
pq.push(now);
}
}
}
}
int main(void) {
#ifndef ONLINE_JUDGE
freopen("E:\\input.txt","r",stdin);
#endif // ONLINE_JUDGE
int kase=0,T,n,m,c;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&c);
init();
int lay[maxv]={0};
bool visit_lay[maxv]={false};
for(int i=1;i<=n;i++)
scanf("%d",&lay[i]),visit_lay[lay[i]]=true;
for(int i=1;i<n;i++)//层与层建边
if(visit_lay[i]==true&&visit_lay[i+1]==true)
addedge(n+i,n+i+1,c),addedge(n+i+1,n+i,c);
for(int i=1;i<=n;i++){
addedge(n+lay[i],i,0);
if(lay[i]>1)//这里必须要用两个if,我第一开始写了个add(i,lay[i]+n,c)
//但是很明显有个问题,就是同一层的两个点,花费代价c就能到达,但是这明显不符合题意的
addedge(i,n+lay[i]-1,c);
if(lay[i]<n)
addedge(i,n+lay[i]+1,c);
}
int u,v,w;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&u,&v,&w),addedge(u,v,w),addedge(v,u,w);
Dijkstra(1,head,edge,dis,visit);
printf("Case #%d: ",++kase);
if(dis[n]<INF)
printf("%d\n",dis[n]);
else
printf("-1\n");
}
return 0;
}