poj3662

题目大意:有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 }
View Code
原文地址:https://www.cnblogs.com/shuzy/p/3812789.html