给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
Input
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
Output
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
Sample Input
2 2 1 0 1 1 1 0 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 ", res); 144 } 145 146 int main() { 147 init(); 148 solve(); 149 return 0; 150 }