Codeforces Round #575 (Div. 3) F. K-th Path

传送门

题意:

这道题把我看得懵懵的(不敢相信),其实就是给你n个点和m条边(无向图),你要找出来任意两点之间的的最短距离,然后再从其中找出来第k个最小值

 

题解:

正常思维就是floyd多源最短路算法跑一遍,然后把任意两点之间的距离取出来放在数组里面,再排序。之后打印出第k个就可以了

但是n的范围是2e5,然而数组开不了这么大的,所以这里有一点优化的。因为要求第k大的距离,所以我们对所有边排序,取出来前k条边,用这k条边的端点(可以离散化把点的值变小)来重新构造一个图

至于为什么可以这样做,我们可以实践一下,如果这k条边互相不相连,那么第k个大的边(而且这个边还是最短的,正好相当于两点之间的最短路),正好符合题意(因为我们这k条边是在所有边中最小的k个,其他的边肯定要大于等于它)

如果相连了,那么也可以构造出来新的更短的距离,只有这个新的两点之间的距离小于等于咱们挑出来的边才会使用到,所以这样也符合题意

 

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<map>
  6 #include<set>
  7 #include<vector>
  8 #include<algorithm>
  9 #include<queue>
 10 #include<unordered_map>
 11 #include<list>
 12 using namespace std;
 13 #define ll long long 
 14 const int mod=1e9+7;
 15 const ll int inf=1e18+7;
 16  
 17 const int maxn=4e5+5;
 18  
 19 typedef struct
 20 {
 21     int u;
 22     int v;
 23     ll int w;
 24 }St;
 25 St sum[maxn];
 26  
 27 bool cmp(const St &a,const St &b)
 28 {
 29     return a.w < b.w;
 30 }
 31  
 32 int n,m,k;
 33  
 34 ll int e[2005][2005];
 35  
 36 void init()
 37 {
 38     for(int i=0;i<=1505;i++)
 39     {
 40         for(int j=0;j<=1505;j++)
 41         {
 42             if(i==j)
 43                 e[i][j]=0;
 44             else
 45                 e[i][j]=inf;
 46         }
 47     }
 48 }
 49  
 50 int main()
 51 {
 52     ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 53     
 54     init();
 55     
 56     cin>>n>>m>>k;
 57     
 58     vector<ll int>v;
 59     
 60     for(int i=0;i<m;i++)
 61         cin>>sum[i].u>>sum[i].v>>sum[i].w;
 62     
 63     sort(sum,sum+m,cmp);
 64     
 65     for(int i=0;i<min(m,k);i++)
 66     {
 67         v.push_back(sum[i].u);
 68         v.push_back(sum[i].v);
 69     }
 70     
 71     //离散化 
 72     sort(v.begin(),v.end());//排序 
 73     v.erase(unique(v.begin(),v.end()),v.end());//去重 
 74     
 75     int now=v.size();
 76     
 77     for(int i=0;i<min(m,k);i++)
 78     {
 79         sum[i].u=lower_bound(v.begin(),v.end(),sum[i].u)-v.begin()+1;//加一防止点从0开始 
 80         sum[i].v=lower_bound(v.begin(),v.end(),sum[i].v)-v.begin()+1;
 81         
 82         e[sum[i].u][sum[i].v]=sum[i].w;
 83         e[sum[i].v][sum[i].u]=sum[i].w; 
 84         
 85     }
 86     
 87     for(int k=1;k<=now;k++)
 88     {
 89         for(int i=1;i<=now;i++)
 90         {
 91             for(int j=1;j<=now;j++)
 92             {
 93                 if(e[i][k]+e[k][j]<e[i][j])
 94                 {
 95                     e[i][j]=e[i][k]+e[k][j];
 96                 }
 97             }
 98         }
 99     }
100     
101     vector<ll int>edge;
102     
103     for(int i=1;i<=now;i++)
104     {
105         for(int j=i+1;j<=now;j++)
106         {
107             edge.push_back(e[i][j]);
108         }
109     }
110     
111     sort(edge.begin(),edge.end());;
112     
113     cout<<edge[k-1]<<endl;
114     
115     return 0;
116 }
View Code

 

转载于:https://www.cnblogs.com/kongbursi-2292702937/p/11538386.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值