K-th Path

原题解链接戳这里

校内训练赛的T1...

简单说一下题意:

有n个点,m条边的无向图。某两点间将可以有一个最短路径。不同组合(vi,vj)的最短路径中,输出第k小的最短路径长度。

n<=2e5。

显而易见,暴力跑算法是不可取的。注意到k很小,可以考虑重新构图。

我们可以取出图中前k小的路,再以这些路径所连接的点重新构造一张小图。则小图的v<=400。轻轻松松Floyd。

可以感性证明一下子:这k小路径构成的点,互相之间的最短路径也一定是在原图中前k小。缩短路径规模就可以轻松跑算法了

我们把边连接的点取出来后,unique一下,去重。因为可能连接的点有(1,2)(2,3),我们只需要123。

然后利用lower_bound抛弃选出来的点在原图中的编号,直接给予新的编号。反正最后只需要边长无所谓点。

不要忘记longlong。

#include <iostream>
#include <cstdio>
#include <algorithm>
#define R register
#define N 200005
typedef long long ll;
long long INF=1ll<<60;
using namespace std;
int n,m,k,b[1000],cnt,cnt1;
long long mp[805][805],d[N];
struct node{int u,v,w;}a[N];
bool cmp(node x,node y){return x.w<y.w;}
inline int ri(){
    char c=getchar();int x=0,w=1;
    while(!isdigit(c)){if(c=='-')w=-1;c=getchar();}
    while( isdigit(c)){x=(x<<3)+(x<<1)+c-48;c=getchar();}
    return x*w;
}
int main(){
    n=ri(),m=ri(),k=ri();
    for(R int i=1;i<=m;i++)
        a[i].u=ri(), a[i].v=ri(), a[i].w=ri();
    sort(a+1,a+m+1,cmp);
    for(R int i=1;i<=min(m,k);i++) 
        b[++cnt]=a[i].u, b[++cnt]=a[i].v;
    sort(b+1,b+cnt+1);
    cnt=unique(b+1,b+cnt+1)-b-1;
    for(R int i=1;i<=cnt;i++)
        for(R int j=1;j<=cnt;j++)
            mp[i][j]=INF;
    for(R int i=1;i<=min(m,k);i++){
        int u=lower_bound(b,b+cnt+1,a[i].u)-b;
        int v=lower_bound(b,b+cnt+1,a[i].v)-b;
        mp[u][v]=mp[v][u]=a[i].w;
    }
    for(R int q=1;q<=cnt;q++)
        for(R int i=1;i<=cnt;i++)
            for(R int j=1;j<=cnt;j++)
                if(mp[i][j]>mp[i][q]+mp[q][j])
                    mp[i][j]=mp[i][q]+mp[q][j];
    for(R int i=1;i<=cnt;i++)
        for(R int j=i+1;j<=cnt;j++)
            if(mp[i][j]!=INF)d[++cnt1]=mp[i][j];
    sort(d,d+cnt1+1);
    printf("%lld
",d[k]);
    return 0;
}
原文地址:https://www.cnblogs.com/flicker-five/p/11598188.html