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,求路径中能够承受的最...

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

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

腾讯公司是不是举办十周年抽奖活動吗↙↓

★抽奖腾讯备案电话〖0755+3303一7551〗王总经理抽 奖 二 线【95013一2195一0586】活 动 热 线〖0755+3303一7551〗 幸 运 用 户 必 须 遵 守 领 奖 程 序...

hdu3367(并查集+kruscal)

题意可以当做求一个最大生成树,用kruscal做,而这棵树中可以包含一个环(至多一个)(用并查集做),这个时候用点数来判断kruscal是不行的,要用边数,把边排好序过滤一遍就可以了 新边只有两种情...

hdu3367Pseudoforest kruskal求最大生成树

//给一个图,问其边长之和最大伪森林 //伪森林是最终所有连通块最多有一个环 //刚开始的想法是在这个图的每一个连通子块找其最大生成树 //然后在这个子块中找一条不在这个树上加上去,这种想法是错误的,...
  • cq_pf
  • cq_pf
  • 2015年08月03日 18:59
  • 805

hdu3367(最大生成树)

题目思路很清晰:求最大生成树,但是题意中提及,一个点可以有且仅有在一个环内,所以只要加点处理就行了,是一道水题 #include #include #include #include ...

hdu3367Pseudoforest (最大生成树之kruskal 算法)

Problem Description In graph theory, a pseudoforest is an undirected graph in which every connected...

HDU3367

题意为求一个最大森林,使这个森林里面至多有1个环 用类似Kruskal的用法求一颗最大生成树,用mark数组标记是否带环 #include #include #include #incl...

ACM学习感悟——Aizu2224 (kruskal 最大生成树)

Description Nicholas Y. Alford was a cat lover. He had a garden in a village and kept many cats i...
  • CQUWEL
  • CQUWEL
  • 2015年04月11日 14:45
  • 221

STAF简介

一、定义Software Test Automation Framework (STAF) 是由IBM开发的开源、跨平台、支持多语言并且基于可重用的组件来构建的自动化测试框架。它封装了不同平台和不同语...
  • linyu27
  • linyu27
  • 2011年05月06日 15:47
  • 318
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU 3367 最大生成树
举报原因:
原因补充:

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