题目大意
给定一张 个点 条边的无向图,每条边为黑色或白色,求一棵生成树使得其中恰好有 条黑色的边,输出任意一种方案。
一开始想优先加黑边做生成树,如果超过 条再考虑怎么去掉,但断边的话好像要用到LCT……
如果优先加白边,就可以得到哪些黑边是必须加的。
那么先把必须加的黑边加上,然后随意找其他的黑边填满 条,再添白边即可。
因为如果两个点既可以通过黑边连通,也可以通过白边连通,那么加哪条边是无所谓的。
#include <cstdio>
#include <algorithm>
const int N = 20005, M = 100005;
struct Edge {
int u, v, c;
bool f;
} e[M];
int fa[N], n, m, k;
int read() {
int x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x;
}
bool cmp1(Edge a, Edge b) {
return a.c > b.c;
}
bool cmp2(Edge a, Edge b) {
return a.c < b.c;
}
int find(int x) {
if (x != fa[x]) fa[x] = find(fa[x]);
return fa[x];
}
int main() {
n = read(), m = read(), k = read();
for (int i = 1; i <= m; ++i)
e[i].u = read(), e[i].v = read(), e[i].c = read();
std::sort(e + 1, e + m + 1, cmp1);
for (int i = 1; i <= n; ++i) fa[i] = i;
for (int i = 1; i <= m; ++i) {
int fx = find(e[i].u), fy = find(e[i].v);
if (fx != fy) {
fa[fx] = fy;
if (e[i].c == 0) e[i].f = 1;
}
}
int cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= n; ++i) fa[i] = i;
for (int i = 1; i <= m; ++i)
if (e[i].f) fa[find(e[i].u)] = find(e[i].v), ++cnt1, ++cnt2;
std::sort(e + 1, e + m + 1, cmp2);
for (int i = 1; i <= m; ++i) {
int fx = find(e[i].u), fy = find(e[i].v);
if (fx != fy) {
if (e[i].c == 0) {
if (cnt1 == k) continue;
++cnt1;
}
fa[fx] = fy, e[i].f = 1, ++cnt2;
}
}
if (cnt1 != k || cnt2 != n - 1) puts("no solution");
else {
for (int i = 1; i <= m; ++i)
if (e[i].f) printf("%d %d %d\n", e[i].u, e[i].v, e[i].c);
}
return 0;
}