最小生成树与次小生成树

题意:给出两个不同方案,每个方案使得所有的城堡被连通(形成连通图),同时使边权之和尽量小,问第一个方案与第二个方案的大小关系。

解题思路:
因为m个桥能使n个城堡联通,而两个大爷的方案中至少存在一个桥不相同,那么我们判断这是一个求次小生成树的方法。
求次小生成树模板:
https://blog.csdn.net/alice_991/article/details/48225949
枚举+删边+再求MST复杂度有点高,看题解上面容易tle,所以采用上面链接里面的那种算法,为了复习并查集就用了Kruskal,复杂度为(N*2)

#include<cstdio>
#include<algorithm>
typedef long long ll;
using namespace std;

const int maxn = 2e5+5;
struct node {
    int u, v;
    ll w;
    bool operator < (node& rhs) {
        return w < rhs.w;
    }
}g[maxn];
int n, m, pre[2005];

int findset(int x) {
    return x == pre[x] ? pre[x] : pre[x] = findset(pre[x]);
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        pre[i] = i;
    }
    int x, y;
    ll w;
    for (int i = 0; i < m; i++) {
        scanf("%d%d%lld", &x, &y, &w);
        g[i].u = x; 
        g[i].v = y; 
        g[i].w = w;
    }
    int v1 = 0, v2 = 0, i, j;
    sort(g, g + m);
    for (i = 0; i < m; ) {
        for (j = i; j < m && g[j].w == g[i].w; j++) {
            int u = findset(g[j].u);
            int v = findset(g[j].v);
            if (u != v) v1++;
        }
        for (j = i; j < m && g[j].w == g[i].w; j++) {
            int u = findset(g[j].u);
            int v = findset(g[j].v);
            if (u != v) {
                v2++; pre[u] = v;
            }
        }
        if (v2 == n - 1) break;
    }
    if (v2 < n - 1 || v1 > v2) printf("zin\n");
    else printf("ogisosetsuna\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38995588/article/details/80620706