HDu-3367 Pseudoforest(偽森林、kruskal変形)

3409 ワード

タイトルリンク:クリックしてリンクを開く
Pseudoforest
Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2401    Accepted Submission(s): 943
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

题意:各连通のサブセットはせいぜい1つのリングしかなくて、与える辺の中で条件の最大の総长を満たすことを求めます
考え方:最大生成ツリーに似ています.しかし、この問題は複数の連通サブセットに分けることができるので、処理の下で最大1つのリングだけがあればいいことに注意してください.
2つの連通サブセットは、リングがあるときは接続できないに違いありません.そうしないと、新しい連通サブセットには2つのリングがあります.
そのうちの1つにループがある場合は接続できますが、新しいコネクションサブセットにループがあることに注意してください.
いずれもループがない場合はもちろん接続でき、新しい連通サブセットにはループがありません.
コード:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 10010
#define M 100100
int n,m;
int pre[N];
int flag[N];
struct Edge
{
    int u,v,w;
} e[M];

void init()
{
    for(int i=0; i<n; i++)
        pre[i]=i;
    memset(flag,0,sizeof(flag));
}
bool cmp(Edge a,Edge b)
{
    return a.w>b.w;
}
int finds(int x)
{
    int r=x;
    while(r!=pre[r])
        r=pre[r];
    int j;
    while(x!=pre[x])
    {
        j=x;
        x=pre[x];
        pre[j]=r;
    }
    return r;
}
int kruskal()
{
    int ans=0,x,y;
    for(int i=0; i<m; i++)
    {
        x=finds(e[i].u);
        y=finds(e[i].v);
        if(x==y)
        {
            if(!flag[x])
            {
                flag[x]=1;
                ans+=e[i].w;
            }
            continue;
        }
        if(flag[x]&&flag[y]) continue;
        pre[x]=y;
        ans+=e[i].w;
        if(!flag[x]&&!flag[y]) continue;
        flag[x]=flag[y]=1;
    }
    return ans;
}
int main()
{
    int u,v,w;
    while(scanf("%d %d",&n,&m)&&n)
    {
        init();
        for(int i=0; i<m; i++)
            scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
        sort(e,e+m,cmp);
        printf("%d
",kruskal()); } return 0; }