求助WA #1判断了连通和是否达到k条边
查看原帖
求助WA #1判断了连通和是否达到k条边
592133
Mr_Potato楼主2024/10/17 16:56

RT 求助

#include <bits/stdc++.h>
using namespace std;

int n,m,k,cntEdge,cntVer;

struct Edge {
    int u,v,w,use=0;
    Edge() {}
    Edge(int a,int b,int c) : u(a),v(b),w(c) {}
};

vector<Edge> edge;

class DSU {
    int fa[20010];
public :
    void init(int size) {
        for (int i=1; i<=size; ++i) {
            fa[i] = i;
        }
    }
    int find(int x) {
        if (x != fa[x]) {
            fa[x] = find(fa[x]);
        }
        return fa[x];
    }
    void unite(int x,int y) {
        fa[find(x)] = find(y);
    }
} dsu;

// 题意等价于,一个图存在n条权值为0或1的边,求边权和为k的生成树

void calculate() {
    dsu.init(n);
    sort(edge.begin(),edge.end(),[](Edge a,Edge b) {
        return a.w < b.w;  // 把0边放到前面
    });
    for (auto &ver : edge) {
        if (dsu.find(ver.u) != dsu.find(ver.v)) {
            dsu.unite(ver.u,ver.v);  // 0边全部加入
            if (ver.w == 1) { // 统计必加的1边个数(保证连通)
                ++cntEdge;
                ver.use = 1;
                ver.w = -1;
            }
        }
    }
}

void Kruskal() {
    dsu.init(n);
    sort(edge.begin(),edge.end(),[](Edge a,Edge b) {
        return a.w > b.w;  // 把1边放到前面
    });
    for (auto ver : edge) {  // 把必加的边全都加进去
        if (ver.use) {
            dsu.unite(ver.u,ver.v);
            ++cntVer;
        }
    }
    for (auto &ver : edge) {
        if (dsu.find(ver.u) != dsu.find(ver.v)) {
            if (ver.w == 1 and cntEdge < k) {
                dsu.unite(ver.u,ver.v);
                ++cntEdge, ++cntVer;
                ver.use = 1;
            } else if (ver.w == 0 and cntEdge == k) {
                dsu.unite(ver.u,ver.v);
                ++cntVer;
                ver.use = 1;
            }
        }
    }
}

int main() {
    scanf("%d %d %d",&n,&m,&k);
    for (int i=1; i<=m; ++i) {
        int u,v,w;
        scanf("%d %d %d",&u,&v,&w);
        if (w == 0) {  // 鹅卵石路,边权按1算
            edge.push_back({u,v,1});
        } else {       // 水泥路,边权按0算
            edge.push_back({u,v,0});
        }
    }

    // 先对0边(水泥路)跑一遍Kruskal,算出必须要加的1边的个数
    calculate();
    if (cntEdge > k) {  // 边权和至少为cntEdge,则无法达到k,否则不连通
        printf("No solution\n");
        return 0;
    }
    
    Kruskal();
    if (cntEdge < k or cntVer + 1 < n) {
        printf("No solution\n");
        return 0;
    }
    for (auto ver : edge) {
        if (ver.use) {
            printf("%d %d %d\n",ver.u,ver.v,1-(ver.w==-1?1:ver.w));
        }
    }
    return 0;
}
2024/10/17 16:56
加载中...