题意:有一张 n 个顶点,m条边的连通图,m ≤ n+2。每条边可以染成红色或蓝色,然后只考虑红色的边,计算出图里的连通分量数量为 c1,同样只考虑蓝色的边,计算出连通分量的数量为c2,求出最小的 c1 + c2。
思路:我们有一张红色的图和一张蓝色的图,当有图里面出现环时,那么就说明有一条边浪费了,因为即使环里少一条边,这张图的连通分量数是不变的,所以最小的c1 + c2 就是要让两种颜色的图都不出现环。题目保证了 m 条边能构成一张连通图,所以 m ≥ n - 1,我们可以先将能构成一张连通图的 n - 1条边染成同一种颜色,那么这 n - 1条边不会出现环,再将剩下的边染成另一种颜色,因为 m ≤ n+2,所以最多还有三条边,而三条边刚好有可能形成一个环。如果m = n + 2,我们就检查一下多出来的三条边会不会成环,如果会的话,那就把其中一条边染成连通图的那一种颜色,再把连通图中顶点含有这条边的顶点的边颜色修改,那么两张图就都不会成环。
代码:
#include<bits/stdc++.h>
#define pb push_back
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10, P = 1e9 + 7, mod = 998244353;
int f[N];
PII a[N];
int find(int x){
if(x != f[x]) f[x] = find(f[x]);
return f[x];
}
void solve() {
int n, m;
cin >> n >> m;
string ans(m, '0');
for(int i = 1; i <= n; i++) f[i] = i;
set<int> se;
PII b;
for(int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
a[i] = {u, v};
int x = find(u), y = find(v);
if(x == y) ans[i] = '1', se.insert(u), se.insert(v), b = a[i];
else f[x] = f[y];
}
if(se.size() == 3 && m == n + 2) {
for(int i = 0; i < m; i++)
if(a[i] == b) {
ans[i] = '0';
for(int j = 0; j < m; j++) {
if(i != j && (b.first == a[j].first || b.first == a[j].second))
ans[j] = '1';
}
}
}
cout << ans << endl;
}
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int tt = 1;
cin >> tt;
while(tt--) {
solve();
}
return 0;
}