HDU3367 Pseudoforest【最大生成僞森林+變形Kruskal算法】

Pseudoforest

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3998 Accepted Submission(s): 1595

Problem Description
In graph theory, a pseudoforest is an undirected graph in which every connected component has at most one cycle. The maximal pseudoforests of G are the pseudoforest subgraphs of G that are not contained within any larger pseudoforest of G. A pesudoforest is larger than another if and only if the total value of the edges is greater than another one’s.

Input
The input consists of multiple test cases. The first line of each test case contains two integers, n(0 < n <= 10000), m(0 <= m <= 100000), which are the number of the vertexes and the number of the edges. The next m lines, each line consists of three integers, u, v, c, which means there is an edge with value c (0 < c <= 10000) between u and v. You can assume that there are no loop and no multiple edges.
The last test case is followed by a line containing two zeros, which means the end of the input.

Output
Output the sum of the value of the edges of the maximum pesudoforest.

Sample Input
3 3
0 1 1
1 2 1
2 0 1
4 5
0 1 1
1 2 1
2 3 1
3 0 1
0 2 2
0 0

Sample Output
3
5

Source
“光庭杯”第五屆華中北區程序設計邀請賽 暨 WHU第八屆程序設計競賽

問題鏈接HDU3367 Pseudoforest
問題簡述:最大權值的僞森林,要求每個子圖最多隻有1個環。
問題分析
    。
    。
程序說明:(略)
參考鏈接:(略)
題記:(略)

AC的C++語言程序如下:

/* HDU3367 Pseudoforest */

#include <bits/stdc++.h>

using namespace std;

const int N = 10000;
int f[N + 1], c[N + 1];
void UFInit(int n)
{
    for(int i = 0; i <= n; i++)
        f[i] = i;
    memset(c, 0, sizeof(int) * (n + 1));
}

int Find(int a) {
    return a == f[a] ? a : f[a] = Find(f[a]);
}

int main()
{
    int n, m;
    while(~scanf("%d%d", &n, &m) && (n || m)) {
        vector<pair<int, pair<int, int> > > g(m);
        for(int i = 0; i < m; i++)
            scanf("%d%d%d", &g[i].second.first, &g[i].second.second, &g[i].first);

        sort(g.begin(), g.end(), greater<pair<int, pair<int, int> > >());   // 從大到小

        long long ans = 0;
        UFInit(n);
        for(int i = 0; i < m; i++) {
            int a = Find(g[i].second.first);
            int b = Find(g[i].second.second);
            if(a == b) {
                // 2個結點屬於同一棵樹,判斷是否已經成環
                if(c[a] == 0) {
                    c[a] = c[b] = 1;
                    ans += g[i].first;
                }
            } else {
                if(c[a] && c[b]) continue;  // 2個結點都是環
                if(c[a] || c[b]) c[a] = c[b] = 1;   // 只有1個環
                f[a] = b;
                ans += g[i].first;
            }
        }

        printf("%lld\n", ans);
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章