bzoj1196 HNOI2006 公路修建问题
题意:有 n 个点,m 条边。要从这 m 条边中选出 n - 1 条边形成一棵生成树。一条边有两种权值,分别定义为一级与二级,要求①选出的边中边权选用一级的边至少有 k 个,目标是最小化所选边权的最大值。
题解:核心算法二分答案,然后以这个答案求生成树,以 ① 和 共 n - 1 条边作为条件判断
CODE:
/* Author: JDD PROG: bzoj1196 公路修建问题 DATE: 2015.9.22 */ #include <cstdio> #define REP(i, s, n) for(int i = s; i <= n; i ++) #define REP_(i, s, n) for(int i = n; i >= s; i --) #define MAX_N 10005 #define MAX_M 30005 using namespace std; struct node{ int x, y, w1, w2; }E[MAX_M]; int n, m, k, top = 0; #define max(a, b) (a > b ? a : b) void init() { scanf("%d%d%d", &n, &k, &m); REP(i, 1, m - 1) scanf("%d%d%d%d", &E[i].x, &E[i].y, &E[i].w1, &E[i].w2), top = max(top, max(E[i].w1, E[i].w2)); } int F[MAX_N]; int find(int x) { if(F[x] == x) return x; return F[x] = find(F[x]); } bool gao(int x) { REP(i, 1, n) F[i] = i; int cnt = 0; REP(i, 1, m - 1){ if(E[i].w1 > x) continue; int rx = find(E[i].x), ry = find(E[i].y); if(rx != ry) F[ry] = rx, cnt ++; } if(cnt < k) return 0; REP(i, 1, m - 1){ if(E[i].w2 > x) continue; int rx = find(E[i].x), ry = find(E[i].y); if(rx != ry) F[ry] = rx, cnt ++; } if(cnt != n - 1) return 0; return 1; } void doit() { int l = 0, r = top, mid, ans = 0; while(l <= r){ mid = (l + r) >> 1; if(gao(mid)) ans = mid, r = mid - 1; else l = mid + 1; } printf("%d\n", ans); } int main() { init(); doit(); return 0; }