题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1196
看起来和免费道路那道题是有共同点的,但细细一想,其实二者并不一样。免费道路要求恰好有k条鹅卵石路,而本题要求至少k条一级道路。
本题是想让边权最大的边最小(别去想最小生成树的性质!!!),所以可以二分答案,因为必然最大边权越大越容易满足,任意一条边都可以成为一级道路。
我们毕竟是要验证答案,所以应该先加一遍一级道路,然后再去补二级道路,这样才能够保证符合条件的不被判断为不符合条件。
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 inline int get_num() { 7 int num = 0; 8 char c = getchar(); 9 while (c < '0' || c > '9') c = getchar(); 10 while (c >= '0' && c <= '9') 11 num = num * 10 + c - '0', c = getchar(); 12 return num; 13 } 14 15 const int maxn = 1e4 + 5, maxm = 2e4 + 5; 16 17 struct Edge { 18 int u, v, w1, w2; 19 } edge[maxm]; 20 21 int n, k, m, maxw, fa[maxn]; 22 23 int dj_find(int i) { 24 if (fa[i] == i) return i; 25 else return fa[i] = dj_find(fa[i]); 26 } 27 28 inline void dj_merge(int a, int b) { 29 fa[dj_find(a)] = dj_find(b); 30 } 31 32 inline int check(int x) { 33 int cnt = 0; 34 for (int i = 1; i <= n; ++i) fa[i] = i; 35 for (int i = 1; i <= m - 1; ++i) { 36 if (edge[i].w1 > x) continue; 37 int u = edge[i].u, v = edge[i].v; 38 if (dj_find(u) != dj_find(v)) { 39 dj_merge(u, v); 40 ++cnt; 41 } 42 } 43 if (cnt < k) return 0; 44 for (int i = 1; i <= m - 1; ++i) { 45 if (edge[i].w2 > x) continue; 46 int u = edge[i].u, v = edge[i].v; 47 if (dj_find(u) != dj_find(v)) { 48 dj_merge(u, v); 49 ++cnt; 50 } 51 } 52 if (cnt != n - 1) return 0; 53 else return 1; 54 } 55 56 int main() { 57 n = get_num(), k = get_num(), m = get_num(); 58 for (int i = 1; i <= m - 1; ++i) { 59 edge[i].u = get_num(), edge[i].v = get_num(); 60 edge[i].w1 = get_num(), edge[i].w2 = get_num(); 61 maxw = max(maxw, edge[i].w1); 62 } 63 int l = 1, r = maxw; 64 while (l < r) { 65 int mid = l + (r - l) / 2; 66 if (check(mid)) r = mid; 67 else l = mid + 1; 68 } 69 printf("%d", l); 70 return 0; 71 }