图论
传送门
题意:在一个空间中有一个N层图,每一层上分布着一些点(N个点),一层上有多个点
或者没有点,一次只能从第i层跳到第i+1或者i-1层,权值为w,现在给出一些有权边,
问从1到n点的最短路
分析:很明显是最短路,关键在于怎么建图,这就涉及到层与点建边,层与层建边,每一个相邻
层都可以建边。
如图:黑色为题给出的无向边,首先我们可以在每一层建立一个源点Si,然后对于这一
层的每个点i与该源点建一条有向边(Si-->i),且这一层的每个点i需要与上一层和下一层
的源点Si+1,Si-1,都要建有向边(i-->Si+1,i-->Si-1);最后就是两两相邻层之间建无
向边
#include <set>
#include <map>
#include <list>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <bitset>
#include <vector>
#include<cstring>
#include <stdio.h>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline int read(){int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();return s*w;}
const int maxn = 1e6+5;
int n,m,c;
int tot,head[maxn];
ll dis[maxn];
bool vis[maxn];
struct Edge{
int to,next,val;
}edge[maxn];
ll inf=1e17+5;
struct node{
ll dis;int pos;
bool operator<(const node &x)const {
return x.dis<dis;
}
};
void add_edge(int u,int v,int w)
{
edge[tot].to=v;
edge[tot].next=head[u];
edge[tot].val=w;
head[u]=tot++;
}
void Dijskra(int s)
{
priority_queue<node>q;
memset(vis,false,sizeof(vis));
for(int i=0;i<maxn;i++) dis[i]=inf;
q.push({0,s});
dis[s]=0;
while (!q.empty())
{
int x=q.top().pos; q.pop();
if(vis[x]) continue; vis[x]=true;
for(int i=head[x];i!=-1;i=edge[i].next){
int y=edge[i].to;
if(dis[y]>dis[x]+(ll)edge[i].val){
dis[y]=dis[x]+(ll)edge[i].val;
if(!vis[y]) q.push({dis[y],y});
}
}
}
}
struct Node{
int pos,g;
}point[maxn];
bool cmp(Node x,Node y){
return x.g<y.g;
}
int main()
{
int t=read(),cas=0;
while (t--)
{
tot=0;
memset(head,-1,sizeof(head));
n=read(),m=read(),c=read();
for(int i=1;i<=n;i++)
{
int post=read();
add_edge(post+n,i,0);
if(post<n) add_edge(i,post+n+1,c);
if(post>1) add_edge(i,post+n-1,c);
}
for(int i=1;i<=m;i++){
int u=read(),v=read(),w=read();
add_edge(u,v,w);
add_edge(v,u,w);
}
Dijskra(1);
printf("Case #%d: ",++cas);
if(dis[n]==inf) puts("-1");
else printf("%lld\n",dis[n]);
}
return 0;
}
```