分层图最短路

分层最短路用更加具体或者形象一点的说法就是有限制的最短路径问题。
通常是拆点解决问题,原图中的点加上一个当前点的状态,成为一个新的点

P4568 [JLOI2011] 飞行路线

P4568 [JLOI2011] 飞行路线

#include <bits/stdc++.h> 
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back
#define inf 0x3f3f3f3f

using namespace std;

void solve()
{
	int n,m,k;
	cin>>n>>m>>k;
	int s,t;
	cin>>s>>t;
	vector<vector<pii>>g(n+1);
	rep(i,1,m){
		int u,v,w;
		cin>>u>>v>>w;
		//无向图,建双向边
		g[u].pb({v,w});
		g[v].pb({u,w});
	}
	struct node{
		int val,u,cnt;
		//大根堆只能重载小于号,小根堆只能重载大于号
		bool operator<(const node&t)const{
			return val>t.val;
		}
	};
	priority_queue<node>q;
	vector<vector<int>>d(n+1,vector<int>(k+1,0x3f3f3f3f));
	vector<vector<int>>vis(n+1,vector<int>(k+1));
	d[s][0]=0;
	q.push({0,s,0});
	while(q.size()){
		auto t=q.top();
		q.pop();
		int val=t.val,u=t.u,cnt=t.cnt;
		if(vis[u][cnt])	continue;
		vis[u][cnt]=1;
		for(auto it:g[u]){
			int v=it.x,w=it.y;
			//不用免费的机会
			if(d[v][cnt]>d[u][cnt]+w){
				d[v][cnt]=d[u][cnt]+w;
				q.push({d[v][cnt],v,cnt});
			}
			//用免费的机会
			if(cnt<k&&d[v][cnt+1]>d[u][cnt]){
				d[v][cnt+1]=d[u][cnt];
				q.push({d[v][cnt+1],v,cnt+1});
			}
		}
	}
	int res=0x3f3f3f3f*1ll;
	rep(i,0,k){
		res=min(res,d[t][i]);
	}
	cout<<res<<endl;
}

signed main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
//   	freopen("1.in", "r", stdin);
	int _;
//	cin>>_;
//	while(_--)
	solve();
	return 0;
}

posted @ 2024-02-15 15:22  cxy8  阅读(9)  评论(0编辑  收藏  举报