#分层图最短路,Dijkstra#洛谷 4568 [JLOI2011]飞行路线

题目

一个无向图,每条边都有花费,可以有\(k\)次挑选边去除花费的机会,问从指定起点到指定终点的最小花费


分析

考虑用分层最短路完成,也就是在同一层走需要花费,不同层走不用花费,最终走到最底层,然后需要建\(k\)层,再跑一个\(\text{Dijkstra}\)就可以了


代码

#include <cstdio>
#include <cctype>
#include <queue>
#include <cstring>
#define rr register
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=110011;
struct rec{
    int w,u;
    bool operator <(const rec &t)const{
	    return w>t.w;
	}
};
struct node{int y,w,next;}e[N*20]; bool v[N];
int n,m,cnt,k,st,en,ans,ls[N],dis[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
inline void add(int x,int y,int w){e[++cnt]=(node){y,w,ls[x]},ls[x]=cnt;};
priority_queue<rec>q;
signed main(){
	n=iut(),m=iut(),k=iut(),st=iut()+1,en=iut()+1;
	for (rr int i=1;i<=m;++i){
		rr int x=iut()+1,y=iut()+1,w=iut();
		add(x,y,w),add(y,x,w);
		for (rr int j=1;j<=k;++j){
			add(x+j*n,y+j*n,w),add(x+j*n-n,y+j*n,0),
			add(y+j*n,x+j*n,w),add(y+j*n-n,x+j*n,0);
		}
	}
	memset(dis,42,sizeof(dis)),dis[st]=0;
	q.push((rec){0,st}),ans=dis[0];
	while (q.size()){
		rr rec t=q.top(); rr int x=t.u,now=t.w; q.pop();
		if (dis[x]!=now||v[x]) continue; v[x]=1;
		for (rr int i=ls[x];i;i=e[i].next)
		if (dis[e[i].y]>dis[x]+e[i].w){
			dis[e[i].y]=dis[x]+e[i].w;
			q.push((rec){dis[e[i].y],e[i].y});
		}
	}
	for (rr int i=0;i<=k;++i) ans=min(ans,dis[i*n+en]);
    return !printf("%d",ans);
}
posted @ 2020-01-15 16:58  lemondinosaur  阅读(123)  评论(0编辑  收藏  举报