题目:
Pseudoforest |
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) |
Total Submission(s): 283 Accepted Submission(s): 122 |
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第八届程序设计竞赛
|
Recommend
lcy
|
题目分析:
求有一个环的最大生成树。
1、要求最大生成树,这时候我们只需要把从小到大的排序函数改成从大到小排序即可。如:
bool cmp(Edge a,Edge b){
return a.weight > b.weight;
}
2、如何保证有一个环?
1)如果是两棵树在进行合并操作
两棵树都有环,不能进行合并操作。
如果只有一个数有环,可以进行合并操作。合并前先做一下标记。
如果都没有环,可以进行合并操作。
2)如果是是同一颗树在进行合并操作。
那么这棵树合并前必然不能有环。
代码如下:
/*
* h.cpp
*
* Created on: 2015年3月11日
* Author: Administrator
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10001;
const int maxm = 100001;
int father[maxn];
struct Edge{
int begin;
int end;
int weight;
}edges[maxn*maxn];
int visited[maxn];//用来标记以某一结点为根节点的最大生成树中是否已经有环.如visited[i]=true.表示以i为根节点的最大生成树中已经有环
int find(int a){
if(a == father[a]){
return a;
}
return father[a] = find(father[a]);
}
/**
* 求有一个环的最大生成树
*/
int kruscal(int count){
int sum = 0;
int i;
for(i = 0 ; i < maxn ; ++i){
father[i] = i;
}
for(i = 0 ; i < count ; ++i){//注意这里的边的索引从0开始,从1开始这道题莫名其妙的WA
int fa = find(edges[i].begin);
int fb = find(edges[i].end);
if(fa != fb){//如果是两棵树
if(visited[fa] == true && visited[fb] == true){//并且他们都已经有环
continue;//不能合并,继续拧下一次循环
}
if(visited[fa] || visited[fb]){//如果其中有一棵树有环了.可以继续执行
visited[fa] = visited[fb] = true;//合并以后将这两棵树都标记位已经有环
}
//合并操作
sum += edges[i].weight;
father[fa] = fb;
}else if(visited[fa] == false){//如果是同一棵树,并且还没有环
/**
* 则能进行合并操作。为什么呢?
* 同一棵树的合并操作,必然会导致又多出一个环.
* 所以只有在原来还没有环的秦光霞才能继续拧合并
*/
sum += edges[i].weight;
visited[fa] = true;
}
}
return sum;
}
bool cmp(Edge a,Edge b){
return a.weight > b.weight;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF,n){
memset(visited,false,sizeof(visited));
int i;
for(i = 0 ; i < m ; ++i){
scanf("%d%d%d",&edges[i].begin,&edges[i].end,&edges[i].weight);
}
sort(edges,edges+m,cmp);
printf("%d\n",kruscal(m));
}
return 0;
}