校内训练赛的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; }