Acwing340. 通信线路 分层图最短路

题目链接

https://www.acwing.com/problem/content/description/342/

题意

给定带权无向图,从1-n路径上第k+1大边权最小是多少?

思路

维护路径上的最大权/最小权很简单,更改dis定义即可,现在问题是如何记录第k+1大的边。第k+1大的边其实可以相当于在跑最短路过程中,无视了k条最大的边,这点在原题干中更易想出,题意抽象之后反而需要头脑转个弯。

第一次接触分层图,分层图是当对点有不同操作时建立多张图。在这道题中,我们可以建立k+1张图,对于边(u,v),我们除了在每一张图中连接,还要遍历将第i张图的u和第i+1张图的v;第i张图的v和第i+1张图的u相连,边权为0。在低层向高层“跑”权为0的边的时候,就相当于跳过了这条边的边权,那么跳过k次后会从第一层到达第k+1层,在这种情况下跑出的第k+1层终点的“距离”就是所求。

代码

#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=1050*1050;
	const int maxe=20000+maxn; 
	const int inf=0x3f3f3f3f;
	int n,m;
	int head[maxn];
	struct Edge{
    
    
		int to;
		int next;
		int w;
	} edge[maxe];
	int cnt;
	
 	int dis[maxn];
	void init(){
    
    
		cnt=0;
		memset(head,-1,sizeof(head));
		return ;
	}
	inline void add(int u,int v,int w){
    
    
		edge[cnt].next=head[u];
		edge[cnt].to=v;
		edge[cnt].w=w;
		head[u]=cnt;
		cnt++;
	}
	typedef pair<int,int> P;
	void dij(int start){
    
    
		memset(dis,0x3f,sizeof(dis));
		priority_queue<P,vector<P>,greater<P> > q;
		dis[start]=0;
		q.push(P(0,start));
		while(!q.empty()){
    
    
			P p=q.top(); q.pop();
			int v=p.second;
			if(dis[v]<p.first)		continue;
			for(int i=head[v];~i;i=edge[i].next){
    
    
				int tmp=edge[i].to;
				if(dis[tmp]>max(dis[v],edge[i].w)){
    
    
					dis[tmp]=max(dis[v],edge[i].w);
					q.push(P(dis[tmp],tmp));
				}
			}
		}
		return ;
	}

	int main(){
    
    
		IOS
		init();
		int n,p,k;
		cin>>n>>p>>k;
		while(p--){
    
    
			int u,v,w;
			cin>>u>>v>>w;
			add(u,v,w);add(v,u,w);
			for(int i=0;i<k;i++){
    
    
				add(u+n*i,v+n*i+n,0);
				add(v+n*i,u+n*i+n,0);
				add(u+n*i+n,v+n*i+n,w);
				add(v+n*i+n,u+n*i+n,w);
			}
		}
		dij(1);
		if(dis[n+k*n]==inf)
			dis[n+k*n]=-1;
		cout<<dis[n+k*n]<<endl;
		return 0;
	}

	

猜你喜欢

转载自blog.csdn.net/TheSunspot/article/details/108896732