CodeForces

题目链接

题目大意

  给你一张图,图里有很多连通块,你可以将一条边中的一个点去掉连到另外一个点上,问你将整张图变成连通图的最小代价。

解题思路

  我们如果要使两个连通块相连的话,去掉的那个点一定不能是割点,所以每次连接的时候去掉一个连通块上不是割点的点,然后让其和另一个连通块上的任意一个点相连就行了。如果一个点是割点的话,按dfs的访问顺序必定不是最后访问的那个点,所以说我们只要求出每个连通块最后访问的那个点以及对应的边就行了。

代码

const int maxn = 2e5+10;
struct E {
    int to, nxt;
} e[maxn<<1];
P eg[maxn];
int h[maxn], tot, n, m, vec[maxn];
int vis[maxn], lst1[maxn], lst2[maxn], tot2;
void add(int u, int v) {
    e[++tot] = {v, h[u]};
    h[u] = tot;
}
int find(int x) {
    return lower_bound(vec+1, vec+n+1, x)-vec;
}
void dfs(int u) {
    lst1[tot2] = u; vis[u] = 1;
    for (int i = h[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (vis[v]) continue;
        //cout << i << ' ' << tot2 << endl;
        lst2[tot2] = i;
        dfs(v);
    } 
}
struct I {
    int id, u, v;
};
int main() {
    int __; cin >> __;
    while(__--) {
        cin >> m; n = tot = tot2 = 0;
        for (int i = 1, a, b; i<=m; ++i) {
            scanf("%d%d", &a, &b);
            eg[i] = {a, b};
            vec[++n] = a, vec[++n] = b;
        }
        sort(vec+1, vec+n+1);
        n = unique(vec+1, vec+n+1)-vec-1;
        for (int i = 1; i<=m; ++i) {
            int u = find(eg[i].first);
            int v = find(eg[i].second);
            add(u, v); add(v, u);
        }
        for (int i = 1; i<=n; ++i)
            if (!vis[i]) ++tot2, dfs(i);
        vector<I> ans;
        //cout << tot2 << endl;
        for (int i = 2; i<=tot2; ++i) ans.push_back({lst2[i], lst1[i], lst1[1]});
        cout << ans.size() << endl;
        for (auto v : ans) printf("%d %d %d
", (v.id+1)/2, vec[v.u], vec[v.v]);
        for (int i = 0; i<=n; ++i) h[i] = vis[i] = lst1[i] = lst2[i] = 0; 
    }
    return 0;
}
原文地址:https://www.cnblogs.com/shuitiangong/p/14488210.html