首页 > 代码库 > bzoj 2654 tree - 二分法 - 最小生成树

bzoj 2654 tree - 二分法 - 最小生成树

<style></style>
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。

Input

第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

Output

一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。

Sample Input

2 2 10 1 1 10 1 2 0

Sample Output

2

Hint

原数据出错,现已更新 by liutian,但未重测---2016.6.24


  显然是MST,但是在Kruskal的过程中我们无法控制白边的数量。如果考虑修改边值,可以发现如果给白边的边权都加上一个delta,那么白边的数量随着delta的增大而减小。所以可以二分它去控制白边的数量。

Code

  1 /**  2  * bzoj  3  * Problem#2654  4  * Accepted  5  * Time:1892ms  6  * Memory:3052k  7  */  8 #include<iostream>  9 #include<cstdio> 10 #include<ctime> 11 #include<cctype> 12 #include<cstring> 13 #include<cstdlib> 14 #include<fstream> 15 #include<sstream> 16 #include<algorithm> 17 #include<map> 18 #include<set> 19 #include<stack> 20 #include<queue> 21 #include<vector> 22 #include<stack> 23 #ifndef WIN32 24 #define Auto "%lld" 25 #else 26 #define Auto "%I64d" 27 #endif 28 using namespace std; 29 typedef bool boolean; 30 const signed int inf = (signed)((1u << 31) - 1); 31 #define smin(a, b) a = min(a, b) 32 #define smax(a, b) a = max(a, b) 33 #define max3(a, b, c) max(a, max(b, c)) 34 #define min3(a, b, c) min(a, min(b, c)) 35 template<typename T> 36 inline boolean readInteger(T& u){ 37     char x; 38     int aFlag = 1; 39     while(!isdigit((x = getchar())) && x != - && x != -1); 40     if(x == -1) { 41         ungetc(x, stdin); 42         return false; 43     } 44     if(x == -){ 45         x = getchar(); 46         aFlag = -1; 47     } 48     for(u = x - 0; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - 0); 49     ungetc(x, stdin); 50     u *= aFlag; 51     return true; 52 } 53  54 typedef class union_found{ 55     public: 56         int *f; 57         union_found():f(NULL) {} 58         union_found(int points) { 59             f = new int[(const int)(points + 1)]; 60             clear(points); 61         } 62         int find(int x) { 63             if(f[x] != x)    return f[x] = find(f[x]); 64             return f[x]; 65         } 66         void unit(int fa, int so) { 67             int ffa = find(fa); 68             int fso = find(so); 69             f[fso] = ffa; 70         } 71         boolean connected(int a, int b) { 72             return find(a) == find(b); 73         } 74         void clear(int points) { 75             for(int i = 0; i <= points; i++) 76                 f[i] = i; 77         } 78 }union_found; 79  80 int delta = 0; 81  82 typedef class Edge { 83     public: 84         int from; 85         int end; 86         int val; 87         boolean col; 88          89         inline int getVal() const { 90             if(col)    return val + delta; 91             return val; 92         } 93 }Edge; 94  95 boolean operator < (const Edge& a, const Edge& b) { 96     return a.getVal() < b.getVal(); 97 } 98  99 int n, m, lim;100 union_found uf;101 Edge* edge;102 103 inline void init() {104     readInteger(n);105     readInteger(m);106     readInteger(lim);107     uf = union_found(n);108     edge = new Edge[(const int)(m + 1)];109     for(int i = 0; i < m; i++) {110         readInteger(edge[i].from);111         readInteger(edge[i].end);112         readInteger(edge[i].val);113         readInteger(edge[i].col);114         edge[i].col ^= 1;115     }116 }117 118 int res = 0;119 int kruskal(int mid) {120     delta = mid;121     res = 0;122     uf.clear(n);123     sort(edge, edge + m);124     int fw = 0, fin = 0;125     for(int i = 0; i < m; i++) {126         if(!uf.connected(edge[i].from, edge[i].end)) {127             uf.unit(edge[i].from, edge[i].end);128             fw += edge[i].col, fin ++, res += edge[i].val;129         }130     }131     return fw;132 }133 134 135 inline void solve() {136     int l = -100, r = 100, c;137     while(l <= r) {138         int mid = (l + r) >> 1;139         if((c = kruskal(mid)) < lim)    r = mid - 1;140         else if(c > lim)    l = mid + 1;141         else break;142     }143     printf("%d\n", res);144 }145 146 int main() {147     init();148     solve();149     return 0;150 }

bzoj 2654 tree - 二分法 - 最小生成树