原題傳送門
轉化題意:求一個有條邊是0邊(鵝卵石路)的生成樹
感覺比較套路
先把所有1邊加入,並查集維護連通性,再加入必須加的0邊,統計出多少條,哪幾條0邊是必須要的
如果必須要的0邊,那麼無解
接下來就重來一次,先把必須加的0邊加入,然後儘可能加到條0邊,然後再儘可能加入1邊
如果加入的0邊,那麼無解
兩次操作之後若不連通也無解
最後就可以輸出了
Code:
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
struct Line{
int x, y, type;
}line[maxn], ans[maxn];
int n, f[maxn], m, k, tot, cnt;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
bool cmp1(Line x, Line y){ return x.type > y.type; }
bool cmp2(Line x, Line y){ return x.type < y.type; }
int getfa(int k){ return k == f[k] ? k : f[k] = getfa(f[k]); }
bool check(){
int tmp = getfa(1);
for (int i = 2; i <= n; ++i) if (getfa(i) != tmp) return 1;
return 0;
}
int main(){
n = read(), m = read(), k = read();
for (int i = 1; i <= m; ++i) line[i] = (Line){read(), read(), read()};
sort(line + 1, line + 1 + m, cmp1);
for (int i = 1; i <= n; ++i) f[i] = i;
for (int i = 1; i <= m; ++i){
int f1 = getfa(line[i].x), f2 = getfa(line[i].y);
if (f1 == f2) continue;
f[f1] = f2;
if (!line[i].type) ++tot, line[i].type = -1;
}
if (tot > k || check()) return puts("no solution"), 0;
sort(line + 1, line + 1 + m, cmp2);
for (int i = 1; i <= n; ++i) f[i] = i;
tot = 0;
for (int i = 1; i <= m; ++i){
int f1 = getfa(line[i].x), f2 = getfa(line[i].y);
if (f1 == f2) continue;
if (line[i].type < 1 && tot < k || line[i].type >= 1)
line[i].type = max(line[i].type, 0), tot += 1 - line[i].type, ans[++cnt] = line[i], f[f1] = f2;
}
if (tot < k || check()) return puts("no solution"), 0;
for (int i = 1; i <= cnt; ++i) printf("%d %d %d\n", ans[i].x, ans[i].y, ans[i].type);
return 0;
}