BZOJ 1196 [HNOI2006]公路修建问题:二分 + 贪心生成树check(类似kruskal)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1196
题意:
n个城市,m对城市之间可以修公路。
公路有两种,一级公路和二级公路,在第i对城市之间修的花费分别为c1[i],c2[i]。
你需要修n-1条公路,连接起所有城市(一棵树),并且至少有k条一级公路。
问你“花费最大的一条公路”的最小花费(最大值最小)。
题解:
O(log(c))二分 * O(m)生成树check + O(mlog(m))预先将边排序
二分:
二分答案(可能的最大一条公路的花费)。
check:
现在二分的值为now,要求所有边的花费 <= now.
所以贪心下:
对于每条边,只要不超过now,并且属于不同集合:能修一级就修一级,不行再修二级,然后加入生成树中。
并且还要先考虑最有可能可以修一级公路的边,所以预先将所有边按c1从小到大排序。
整个过程类似kruskal。。。
最后如果是一棵树(cnt==n-1),并且一级公路数量足够(super>=k),则答案可行。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #include <vector> 6 #define MAX_N 10005 7 #define COST_MAX 30005 8 9 using namespace std; 10 11 struct Edge 12 { 13 int sour; 14 int dest; 15 int fst; 16 int sec; 17 Edge(int _sour,int _dest,int _fst,int _sec) 18 { 19 sour=_sour; 20 dest=_dest; 21 fst=_fst; 22 sec=_sec; 23 } 24 Edge(){} 25 friend bool operator < (const Edge &a,const Edge &b) 26 { 27 return a.fst<b.fst; 28 } 29 }; 30 31 int n,m,k; 32 int ans; 33 int par[MAX_N]; 34 vector<Edge> edge; 35 36 void read() 37 { 38 cin>>n>>k>>m; 39 m--; 40 int a,b,c1,c2; 41 for(int i=0;i<m;i++) 42 { 43 cin>>a>>b>>c1>>c2; 44 edge.push_back(Edge(a,b,c1,c2)); 45 } 46 } 47 48 void init_union_find() 49 { 50 for(int i=1;i<=n;i++) 51 { 52 par[i]=i; 53 } 54 } 55 56 int find(int x) 57 { 58 return par[x]==x?x:par[x]=find(par[x]); 59 } 60 61 void unite(int x,int y) 62 { 63 int px=find(x); 64 int py=find(y); 65 if(px==py) return; 66 par[px]=py; 67 } 68 69 bool same(int x,int y) 70 { 71 return find(x)==find(y); 72 } 73 74 bool check(int now) 75 { 76 init_union_find(); 77 int cnt=0; 78 int super=0; 79 for(int i=0;i<m;i++) 80 { 81 Edge temp=edge[i]; 82 if(min(temp.fst,temp.sec)<=now) 83 { 84 if(!same(temp.sour,temp.dest)) 85 { 86 cnt++; 87 if(temp.fst<=now) super++; 88 unite(temp.sour,temp.dest); 89 } 90 } 91 } 92 return cnt==n-1 && super>=k; 93 } 94 95 void solve() 96 { 97 sort(edge.begin(),edge.end()); 98 int lef=0; 99 int rig=COST_MAX; 100 while(rig-lef>1) 101 { 102 int mid=(lef+rig)/2; 103 if(check(mid)) rig=mid; 104 else lef=mid; 105 } 106 ans=rig; 107 } 108 109 void print() 110 { 111 cout<<ans<<endl; 112 } 113 114 int main() 115 { 116 read(); 117 solve(); 118 print(); 119 }