K-th Path(CF-1196F)

Problem Description

You are given a connected undirected weighted graph consisting of nn vertices and mm edges.

You need to print the k-th smallest shortest path in this graph (paths from the vertex to itself are not counted, paths from i to j and from j to i are counted as one).

More formally, if dd is the matrix of shortest paths, where di,jdi,j is the length of the shortest path between vertices i and j (1≤i<j≤n), then you need to print the kk-th element in the sorted array consisting of all di,jdi,j, where 1≤i<j≤n.

Input

The first line of the input contains three integers n,m and k (2≤n≤2⋅105, n−1≤m≤min(n(n−1)2,2⋅105)n), 1≤k≤min(n(n−1)2,400) — the number of vertices in the graph, the number of edges in the graph and the value of kk, correspondingly.

Then mm lines follow, each containing three integers x, y and w (1≤x,y≤n, 1≤w≤109, x≠y) denoting an edge between vertices x and y of weight w.

It is guaranteed that the given graph is connected (there is a path between any pair of vertices), there are no self-loops (edges connecting the vertex with itself) and multiple edges (for each pair of vertices x and y, there is at most one edge between this pair of vertices in the graph).

Output

Print one integer — the length of the k-th smallest shortest path in the given graph (paths from the vertex to itself are not counted, paths from ii to jj and from jj to ii are counted as one).

Examples

Input

6 10 5
2 5 1
5 3 9
6 2 2
1 3 1
5 1 8
6 5 10
1 6 5
6 4 6
3 6 2
3 4 5

Output

3

Input

7 15 18
2 6 3
5 7 4
6 5 4
3 6 9
6 7 7
1 6 4
7 1 6
7 2 1
4 3 2
3 2 8
5 3 6
2 5 5
3 7 9
4 1 8
2 1 1

Output

9

题意:给出一 n 个点 m 条边的无向带权图,定义路径为任意两点的距离,输出图中第 k 条小的路径

思路:

由于路径定义为任意两点的距离,要在图中找第 k 小的路径,那么第 k 小的路径一定是在前 k 条边所连接的点中的路径中,因此可以对 m 条边进行排序,选前 k 条边,将每条边连接的点记录下来跑 Floyd,然后找第 k 大的边即可

此外,选出来点后,点的编号可能很大,无法建立邻接矩阵,因此需要对点进行离散化再跑 Floyd

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
const int MOD = 1E9+7;
const int N = 5000+5;
const int dx[] = {-1,1,0,0,-1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;
struct Edge {
    LL x,y;
    LL w;
    Edge() {}
    Edge(LL x,LL y,LL w):x(x),y(y),w(w) {}
    bool operator <(const Edge &rhs)const {
        return w<rhs.w;
    }
};
vector<Edge> edge;
vector<LL> node;
LL dis[N][N];
int main() {
    LL n,m,k;
    scanf("%lld%lld%lld",&n,&m,&k);
    for(int i=1;i<=m;i++){
        LL x,y,w;
        scanf("%lld%lld%lld",&x,&y,&w);
        edge.push_back(Edge(x,y,w));
    }
    sort(edge.begin(),edge.end());//将边按权值大小排序

    LL edgeNum=min(m,k);
    for(int i=0;i<edgeNum;i++){//选取前k大的边并记录每条边的邻接点
        LL x=edge[i].x;
        LL y=edge[i].y;
        node.push_back(x);
        node.push_back(y);
    }

    sort(node.begin(),node.end());//将点排序后去重
    node.erase(unique(node.begin(),node.end()),node.end());

    memset(dis,INF,sizeof(dis));
    LL nodeNum=node.size();
    for(int i=0;i<nodeNum;i++)
        dis[i][i]=0;

    for(int i=0;i<edgeNum;i++){//离散化后存点
        LL x=lower_bound(node.begin(),node.end(),edge[i].x)-node.begin();
        LL y=lower_bound(node.begin(),node.end(),edge[i].y)-node.begin();
        dis[x][y]=min(dis[x][y],edge[i].w);
        dis[y][x]=min(dis[x][y],edge[i].w);
    }

    for(int k=0;k<nodeNum;k++)//Floyd求全源最短路
        for(int i=0;i<nodeNum;i++)
            for(int j=0;j<nodeNum;j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);

    vector<LL> res;
    for (int i=0; i<nodeNum;i++)
        for (int j=0;j<i;j++)
            res.push_back(dis[i][j]);

    sort(res.begin(),res.end());

    printf("%lld\n",res[k-1]);//第k小的路径
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值