bzoj2654: tree(最小生成树+二分)
题目
解析
kruscal在做最小生成树时先按权值排序,权值小的先被选到,我们可以通过控制白色边的边权来控制白色边的数量。
我们可以通过二分答案来给白边加某一个值
同时注意两点
- 不要忘记减去给白边加的值
- 排序时白边优先
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m, num, need, ans, tot, sum, cnt;
int fa[N], head[N], w[N];
struct node {
int u, v, w, col;
bool operator <(const node &oth) const {
return w == oth.w ? col < oth.col : w < oth.w;
}
} e[N], tmp[N];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
int kruscal() {
cnt = 0, sum = 0, ans = 0;
for (int i = 1; i <= n; ++i) fa[i] = i;
sort(e + 1, e + 1 + m);
for (int i = 1; i <= m; ++i) {
int x = find(e[i].u), y = find(e[i].v);
if (x == y) continue;
fa[x] = y;
ans += e[i].w;
if (!e[i].col) sum++;
cnt++;
if (cnt == n - 1) break;
}
return sum;
}
bool check(int x) {
for (int i = 1; i <= m; ++i) {
e[i] = tmp[i];
if (!e[i].col) e[i].w += x;
}
return kruscal() >= need;
}
int main() {
ios::sync_with_stdio(false);
cin >> n >> m >> need;
for (int i = 1, x, y, z, c; i <= m; ++i) {
cin >> x >> y >> z >> c;
e[i] = (node) {x + 1, y + 1, z, c};
tmp[i] = (node) {x + 1, y + 1, z, c};
}
int l = -1000, r = 1000;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) l = mid + 1, tot = ans - need * mid;
else r = mid - 1;
}
cout << tot;
return 0;
}
如果哪里有错误或不易理解,还请不吝赐教