1. 程式人生 > >【hdu3367】Pseudoforest(偽森林)

【hdu3367】Pseudoforest(偽森林)

return style pid cmp acm 防止 include 不能 fine

http://acm.hdu.edu.cn/showproblem.php?pid=3367

題目大意

偽森林就是一個無向圖,這個無向圖有多個連通塊且每個連通塊只有一個簡單環。

給你一個無向圖,讓你找這個圖的一個最大生成偽森林(即邊權之和最大)。

題解

考慮到用Kruscal算法搞最大生成樹時,每次加入一條邊之前都必須保證邊的這兩點在之前屬於兩個連通塊,就是為了防止出現環。

即如果加入的邊的兩點在一個沒有環的連通塊裏的話,就會出現一個環。

那麽我們把Kruscal算法改造一下,如果這條邊的兩點在同一個沒有環的連通塊的話,仍然加入這條邊,並把這個連通塊標記有環。把所有的邊都試著加入一遍後就可以得到最終答案。

還要註意如果這條邊的兩點在不同的連通塊,但是兩個連通塊都有環,那麽這條邊也不能加。

#include <iostream>
#include <vector>
#include <algorithm>
#define maxn 10005
using namespace std;
int n, m;
namespace djs
{
int parent[maxn];
bool mark[maxn];
void init()
{
    for (int i = 0; i <= n; i++)
    {
        parent[i] = -1;
        mark[i] 
= false; } } int find(int x) { if (parent[x] < 0) return x; else return parent[x] = find(parent[x]); } bool merge(int x, int y) { x = find(x); y = find(y); if (x != y) // x與y不在一個連通塊 { if (mark[x] && mark[y]) // 兩個連通塊都有環 return false
; else { if (parent[x] > parent[y]) swap(x, y); parent[x] += parent[y]; parent[y] = x; mark[x] |= mark[y]; return true; } } else // x與y在一個連通塊 { if(mark[x]) return false; else // 這個連通塊沒有環,可以加這條邊 { mark[x] = true; return true; } } } } struct edge { int from, to, weight; }; inline bool cmper(const edge &x, const edge &y) { return x.weight > y.weight; } vector<edge> edges; int main() { while (true) { cin >> n >> m; if (n == 0 && m == 0) return 0; djs::init(); edges.clear(); int a, b, c; for (int i = 1; i <= m; i++) { cin >> a >> b >> c; edges.push_back((edge){a, b, c}); } sort(edges.begin(), edges.end(), cmper); int ans = 0; for (int i = 0; i < edges.size(); i++) { if (djs::merge(edges[i].from, edges[i].to)) ans += edges[i].weight; } cout << ans << endl; } return 0; }

【hdu3367】Pseudoforest(偽森林)