1640 Sunny Magic

This gloomy weather continued, we can not help but worry about his health.

51nod Magic School recently launched a magic exchange activity with the theme "Sunny Weather".

N magicians stand according to the formation, and then select N - 1 magic chains to connect the magic power of all the magicians to form a magic circle.

The magic chain is the key to the success of the practice. Each magic chain has a magic value V, and the final effect of magic depends on the sum of the magic values ​​of all magic chains in the array.

Because the magic of changing fate is too violent, we require the maximum value of the magic power of the magic chain in the array to be as small as possible, and at the same time, the sum of the magic power should be as large as possible.

Now given the number of magicians N, the number of magic chains M. Find the maximum effect of this magic circle.
Input
Two positive integers N, M. (1 <= N <= 10^5, N <= M <= 2 * 10^5)

Next M lines, each with three integers A, B, V. (1 <= A, B <= N, INT_MIN <= V <= INT_MAX)

Ensure that the entered data is legal.
Output
Output a positive integer R, representing the sum of the magic values ​​of the qualified magic circles.
Input example
4 6
1 2 3
1 3 1
1 4 7
2 3 4
2 4 5
3 4 6
Output example
12

Ideas: The idea of ​​​​this question is to first calculate the minimum spanning tree, find the magic value Max_Edge of the largest chain in the minimum spanning tree , and then use all magic chains less than or equal to Max_Edge (the maximum value of the magic value of the magic chain that meets the conditions is as much as possible is small ) to obtain the maximum spanning tree (the sum of the magic value satisfying the condition should be as large as possible) .  

最小生成树有两种方法,Prim ( 未经优化)时间复杂度 n^2( n 为顶点数), Kruskal 时间复杂为 mlog2(m),m 为边的总数。

根据输入数据的规模,显而易见要用后者,也就是 Kruskal。

参考代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

typedef long long ll;
typedef struct edge {
    int s, e;
    ll v;
}Edge;

bool cmp1(Edge A, Edge B) {
    return A.v < B.v;
}
bool cmp2(Edge A, Edge B) {
    return B.v < A.v;
}
const int N = 201000;
Edge a[N];
int f[N];
// f[i] != -1
// 则代表 i 与 f[i]之间有一条边

int Find(int x) {
    if(f[x] == -1) return x;
    return f[x] = Find( f[x] );
}

int n, m;
int kruskal_1() {
    // 返回最小生成树的最后一条边的下标 ans
    // Edge[ans].v 为最小生成树中的最大边
    memset(f, -1, sizeof(f)); // 初始化 f[]
    int sroot, eroot;
    int num = 0, ans = 1;
    for(int i=1; i<=m; i++) {
        sroot = Find(a[i].s);
        eroot = Find(a[i].e);
        if(sroot != eroot) {
            num ++;
            ans = i;
            f[sroot] = eroot;
        }
        if(num >= n-1) {
            break;
        }
    }
    if(num >= n-1) {
        return ans;
    }
    else {
        return -1;
    }
}

ll Max_Edge;
ll kruskal_2() {
    // 在所有 小于等于 Max_Edge 的边中求得最大生成树
    memset(f, -1, sizeof(f));

    ll ans = 0, num = 0;
    int sroot, eroot;
    for(int i=1; i<=m; i++) {
        if(a[i].v > Max_Edge)
           continue;
        sroot = Find( a[i].s );
        eroot = Find( a[i].e );
        if(sroot != eroot) {
            num++;
            ans += a[i].v;
            f[sroot] = eroot;
        }
        if(num >= n-1)
            break;
    }
    if(num >= n-1)
        return ans;
    return -1;
}
int main(){
    cin >> n >> m;

    int s, e, v;
    for(int i=1; i<=m; i++) {
        scanf("%d %d %d", &s, &e, &v);
        a[i].s = s, a[i].e = e;
        a[i].v = v;
    }

    sort(a+1, a+m+1, cmp1); // 升序处理
    int index = kruskal_1();
    Max_Edge = a[index].v;

    //cout << Max_Edge << endl;

    sort(a+1, a+m+1, cmp2); // 降序处理
    cout << kruskal_2() ;
    return 0;
}





Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326075669&siteId=291194637