当前位置: 代码迷 >> 综合 >> Acwing340. 通信线路 分层图最短路
  详细解决方案

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

热度:37   发布时间:2024-02-24 14:10:13.0

题目链接

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(){
    IOSinit();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;}