题目地址:https://www.luogu.org/problemnew/show/P4568
Dijkstra:https://blog.csdn.net/u012972031/article/details/83476580
分层图是什么
顾名思义,所谓的"分层图",就是分层的图。
分层图的用处
在某些情况下,需要在普通的图上算法的基础上增加一些特殊功能,如:某些边权值为0,且这些边是由我们动态生成的。这时候裸的Dijkstra显然无法胜任,那么我们就可以考虑一下使用分层图了。
分层图的实现方法
- 第一种:同时建多个图,并将这些图连起来,就像链表一样。
- 第二种:使用一个二维的dis[]数组,第二个下标储存层数。(这种方法比较快)
分层图的具体实现:
- 第一种:
- 第二种:
- 使用DP方式(用于优化性能),在此不再出示图片
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
int s,k,cnt=0,dis[1000010*20],head[1000010*20];
struct Edge{
int v,w,next;
}e[500005*30];
struct Node{
int u,d;
bool const operator <(const Node& a)const{
return d>a.d;
}
};
void addEdge(int u,int v,int w){
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}
void dijkstra(){
dis[s]=0;
priority_queue<Node> q;
q.push((Node){s,0});
while(!q.empty()){
Node n=q.top();q.pop();
int u=n.u,d=n.d;
if(d!=dis[u])continue;
for(int i=head[u];i;i=e[i].next){
int v=e[i].v,w=e[i].w;
if(dis[u]+w<dis[v]){
dis[v]=dis[u]+w;
q.push((Node){v,dis[v]});
}
}
}
}
int main(){
int n,m;
scanf("%d%d%d",&n,&m,&k);
int t;
scanf("%d%d",&s,&t);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
for(int i=0;i<=k;i++){
int ta=i*n+a,tb=i*n+b;//tb往前连,ta往后连
addEdge(ta,tb,c);
addEdge(tb,ta,c);
if(i!=k){//如果不是最后一个图
addEdge(tb,ta+n,0);//tb往前连
addEdge(ta,tb+n,0);//ta往后连
}
}//普通建图
/*
连接节点:遍历所有加的点:
if(是最前面的图&&是最前面的点){
连后面一个图自己后面的和自己
}else if(是最后面的图){
不连
}else{
连后面一个图自己前面的和自己
连后面一个图自己后面的和自己
}*/
}
for(int i=0;i<=n*30;i++)dis[i]=2000000000;
dijkstra();
printf("%d\n",dis[n*k+t]);
return 0;
}