题目大意:有n个节点p条无向边,现在可以选择其中的任意K条免费,如果必须的边多与K跳,则花费多余所需边中权值最大的一个,求最小花费多少。
分析:最短路+二分
我们可以二分答案mid,对于每一个mid求最短路,将最短路中大权值大于mid的边作为免费的集合,否则作为不免费的集合,验证免费集合大小是否大于K
这里有个技巧,就是在求最短路的过程中,把大于mid的边权值变为1,小于的为0那么最后求到的d[e](e为终点)就是需要统计的集合大小
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <set> 5 #include <algorithm> 6 #include <map> 7 #include <queue> 8 #include<vector> 9 #define maxn 1010 10 #define maxm 1000010 11 #define INF 0x3fffffff 12 using namespace std; 13 struct edge { 14 int to,w; 15 edge(){} 16 edge(int _to,int _w){ 17 to=_to;w=_w; 18 } 19 }; 20 typedef pair<int,int> P; 21 int V; 22 vector<edge> G[maxn]; 23 int d[maxn]; 24 int K; 25 int dijkstra(int s,int x){ 26 priority_queue<P,vector<P>,greater<P> >q; 27 for(int i=0;i<V;++i)d[i]=INF; 28 d[s]=0; 29 q.push(P(d[s],s)); 30 while(!q.empty()){ 31 P p = q.top(); 32 q.pop(); 33 int v = p.second; 34 if(d[v]<p.first)continue; 35 for(int i=0;i<G[v].size();++i){ 36 edge e = G[v][i]; 37 int dd = d[v]+(e.w>=x?1:0); 38 if(d[e.to]>dd){ 39 d[e.to]=dd; 40 q.push(P(d[e.to],e.to)); 41 } 42 } 43 } 44 return d[V-1]; 45 } 46 void solve(){ 47 int l =0,r = maxm+10; 48 while(r-l>1){ 49 int mid = (l+r)/2; 50 if(dijkstra(0,mid)>K)l=mid; 51 else r=mid; 52 } 53 int ans = l; 54 if(l>maxm)ans=-1; 55 printf("%d ",ans); 56 } 57 int main (){ 58 int n,m; 59 while(scanf("%d%d%d",&n,&m,&K)!=EOF){ 60 for(int i=0;i<=n;++i)G[i].clear(); 61 V=n; 62 int u,v,w; 63 for(int i=0;i<m;++i){ 64 scanf("%d%d%d",&u,&v,&w); 65 G[u-1].push_back(edge(v-1,w)); 66 G[v-1].push_back(edge(u-1,w)); 67 } 68 solve(); 69 } 70 }