HDU 3367 最大生成树

原创 2015年06月04日 16:33:39
【copy的讨论版】
这题题意理解了好一阵子才明白,  给出一个图,要求出最大的pseudoforest, 所谓pseudoforest就是指这个图的一个子图,这个子图的每个连通分量中最多只能有一个环, 而且这个子图的所有权值之和最大。这个就是所谓的伪森林。

过程类似与kruskal求最小生成树,千万不要直接求最大生成树,一开始时我想到的方法是用kruskal算法求出这个图的最大生成树, 然后给每一棵数再加上一条最大的边,构成一个环。 但是WA得快吐血了。

正确的做法和求最大生成树很类似,但是有一点改变, 因为每个连通分量允许有一个回环, 所以,我们可以在进行合并两颗树时,要判断这两颗树是否有回环,如果两个树都有回环,那么明显不可以合并这两颗树, 如果只有一棵树有回环,那么可以合并,然后标上记号。如果两个都没有回环,那么就直接合并了。

如果有两个点是属于同一棵树上的,那么判断这棵树上是否已有回环,如果没有的话,那么允许有一个回环,可以链接这两点,再标上记号。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<functional>
#include<vector>

using namespace std;
const int maxn = 10005;
const int maxm = 100005;
typedef long long ll;
int n,m;
struct edge{
    int u,v,cost;
    bool operator < (const edge &z) const{
        return z.cost < cost;
    }
}ed[maxm];

int par[maxn];
int rnk[maxn];
int loop[maxn];

void init_union(){
    memset(par,-1,sizeof(par));
    memset(rnk,0,sizeof(rnk));
    memset(loop,0,sizeof(loop));
}
int find(int x){
    while(par[x] >= 0) x = par[x];
    return x;
}
void unite(int x,int y){
    x = find(x);y = find(y);
    if(x == y) return;
    if(rnk[x] < rnk[y]){
        par[x] = y;
        loop[y] += loop[x];
    }else{
        par[y] = x;
        loop[x] += loop[y];
        if(rnk[x] == rnk[y]) rnk[x]++;
    }
}
bool same(int x,int y){
    return find(x) == find(y);
}

void solve(){
    sort(ed,ed+m);
    init_union();
    ll ans = 0;
    for(int i=0;i<m;i++){
        if(!same(ed[i].u,ed[i].v)){
            if(loop[find(ed[i].u)] + loop[find(ed[i].v)] == 2) continue;
            ans += ed[i].cost;
            unite(ed[i].u,ed[i].v);
        }else{
            int fa = find(ed[i].u);
            if(!loop[fa]){
                loop[fa] = 1;
                ans += ed[i].cost;
            }
        }
    }
    printf("%lld\n",ans);
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        if(n == 0 && m == 0) break;
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].cost);
        }
        solve();
    }

    return 0;
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

POJ 1797 Heavy Transportation(最大生成树)

题目链接:http://poj.org/problem?id=1797 题目大意:给定n个顶点,以及m条边的描述,每条边的描述包括:起点、终点、权重。现在要从顶点1出发到达顶点n,求路径中能够承受的最...
  • Jane_JXR
  • Jane_JXR
  • 2017年01月05日 15:11
  • 1892

poj 3723 Conscription 【最大生成树|最大权森林】

题目:poj 3723 Conscription 题意:要征兵n个男兵和m个女兵,每个花费10000元,但是如果已经征募的男士兵中有和将要征募的女士兵关系好的,那么可以减少花费,给出关系,求...
  • y990041769
  • y990041769
  • 2014年12月06日 10:02
  • 3636

几种特殊的生成树

几种特殊的生成树 分类: ACM•图论2012-05-02 09:22 399人阅读 评论(0) 收藏 举报 commandbuildclassstring算法ini 1.(严格)次小生成...
  • pi9nc
  • pi9nc
  • 2013年10月08日 11:17
  • 1763

无向带权图的最小生成树算法——Prim及Kruskal算法思路

边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权。    最小生成树(MST):权值最小的生成树。    生成树和最小生成树的应用:要连通n个城市需要n-1条...
  • lingzhm
  • lingzhm
  • 2015年03月30日 16:09
  • 5313

hdu4786 Fibonacci Tree(最小生成树+最大生成树+01树+理解)

http://acm.hdu.edu.cn/showproblem.php?pid=4786 题意:有n个节点,给你一些白边和黑边,问能否用两色边构造出一棵生成树,且树中白色边的数量为一个Fib...
  • Flynn_curry
  • Flynn_curry
  • 2016年11月13日 20:24
  • 727

HDU 3367 最大生成树

【copy的讨论版】 这题题意理解了好一阵子才明白,  给出一个图,要求出最大的pseudoforest, 所谓pseudoforest就是指这个图的一个子图,这个子图的每个连通分量中最多只能有一个...
  • qq_26572969
  • qq_26572969
  • 2015年06月04日 16:33
  • 1140

k-近邻学习,朴素贝叶斯,期望最大化,最大熵模型算法介绍

k-近邻学习 k-Nearest Neighbor(KNN)1. 算法描述k-近邻学习是一种监督的分类回归方法。工作机制:给定测试样本,基于某种距离度量找出训练集中与其最接近的k和训练样本,然后基于这...
  • wancongconghao
  • wancongconghao
  • 2017年08月21日 21:57
  • 689

hdu 3367 Pseudoforest 最大生成树

传送门:Pseudoforest题目大意就是求最大生成树,但是前提是要组成一个环解题思路按照边的最大到小排序一下,当变为一个环的时候就是要求的最大生成树,当然肯定不是当变为一个环就退出,当变为两个环的...
  • woshinannan741
  • woshinannan741
  • 2016年07月26日 01:51
  • 158

hdu 3367 Pseudoforest(最大生成树)

/*  可以说是一个最大生成树的问题吧,     题意:求出一个最大的子图(子图的每个连通分量最多有一个环)    用kruskal算法求出最大生成树  不过要判断是否有环  2树合并时 :若2个...
  • chenchaoflight
  • chenchaoflight
  • 2013年04月22日 15:11
  • 1096

最小生成树-MST算法详解及代码实现

最小生成树,贪心算法,Kruskal,Prim算法
  • coder_oyang
  • coder_oyang
  • 2015年09月03日 16:34
  • 4554
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU 3367 最大生成树
举报原因:
原因补充:

(最多只允许输入30个字)