HDU 6349 最小生成树

版权声明:欢迎转载,不要求署名~~~ https://blog.csdn.net/shadandeajian/article/details/82429023

传送门:题目

题意:

给定一个图,边是无向边,然后每条边有一个权值和一种颜色,求用特定两种颜色的边组成强连通图,然后问讯 k [ 1 , m ] 边的加权和的最小值。

题解:

题目很好理解,我们只需要分别建两个图,然后分别找两个最小生成树就行了,然后把不是属于最小生成树的边从小到大排个序,最后遍历一下,加到最小生成树的权值和上面去。第一开始套个模板就写完了,但是一直WA,最后发现,忘记当无法生成最小生成树的时候,就不要更新答案了,直接return就行了,这个BUG改了1天。。。顺便更新了一下Kruskal的模板

AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
using namespace std;

const int maxv = 110;
const int maxe = 110;
int ret[maxe];
vector<int> p;
/*******************Kruskal+并查集优化+递归写法*****************************/
//Kruskal处理稀疏图效果优于Prim
//注意:递归可能爆栈

int pre[maxv], cnt;
struct Edge {
    int from, to, val;
    bool operator<(const Edge& rhs)const {
        return val < rhs.val;
    }
} edge[maxe];
void init() {
    cnt = 0;
    memset(pre, -1, sizeof pre);
    p.clear();
}
void addedge(int from, int to, int val) {
    edge[cnt].from = from;
    edge[cnt].to = to;
    edge[cnt++].val = val;
}
int Find(int x) { //并查集
    return pre[x] == -1 ? x : pre[x] = Find(pre[x]);
}
void Kruskal(int n, int m) { //n代表图种总共的顶点数
    sort(edge, edge + cnt);
    int ecnt = 0, ans = 0;
    for (int i = 0; i < cnt; i++) {
        if (ecnt < n - 1) {
            int f1 = Find(edge[i].from);
            int f2 = Find(edge[i].to);
            if (f1 != f2) {
                ans += edge[i].val;
                pre[f1] = f2;
                ecnt++;
            }
            else
                p.emplace_back(edge[i].val);
        }
        else
            p.emplace_back(edge[i].val);
    }
    sort(p.begin(), p.end());
    if (ecnt < n - 1)
        return;
    if (ret[ecnt] == -1)
        ret[ecnt] = ans;
    else
        ret[ecnt] = min(ans, ret[ecnt]);
    int sum = ans;
    for (auto x : p) {
        sum += x;
        ecnt++;
        if (ret[ecnt] == -1)
            ret[ecnt] = sum;
        else
            ret[ecnt] = min(ret[ecnt], sum);
    }
}
/*******************Kruskal+并查集优化+递归写法*****************************/
int main(void) {
    int T, kase = 1;
    cin >> T;
    while (T--) {
        memset(ret, -1, sizeof ret);

        int n, m, t1[maxe], t2[maxe], t3[maxe];
        char ch[maxe];

        cin >> n >> m;
        for (int i = 0; i < m; i++)
            cin >> t1[i] >> t2[i] >> t3[i] >> ch[i];

        init();
        for (int i = 0; i < m; i++) {
            if (ch[i] != 'B')
                addedge(t1[i], t2[i], t3[i]);
            else
                p.emplace_back(t3[i]);
        }
        Kruskal(n, m);

        init();
        for (int i = 0; i < m; i++) {
            if (ch[i] != 'R')
                addedge(t1[i], t2[i], t3[i]);
            else
                p.emplace_back(t3[i]);
        }
        Kruskal(n, m);

        cout << "Case #" << kase++ << ":" << endl;
        for (int i = 1; i <= m; i++)
            cout << ret[i] << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shadandeajian/article/details/82429023
今日推荐