HDU 3367 Pseudoforest(最大生成树+并查集)

来源:互联网 发布:JAVA修改数组指定位置 编辑:程序博客网 时间:2024/06/01 03:59

大意:n个点m条边,问如果每个联通分支中最多有一个环,最后可以组成的最大的权值和是多少。

思路:类似一颗生成树,是的话那么一定是最大生成树。那么怎么判断是不是会有环的形成呢?那么就可以用并查集判断了,所以直接用克鲁斯卡尔算法算最大生成树即可。

概括起来有两种情况:1、两个端点在同一集合,那么判断是不是有环(标记数组判定),2.不在同一集合,如果两边都有环也不可以。

#include<map>#include<cmath>#include<queue>#include<cmath>#include<string>#include<cstdio>#include<stack>#include<iostream>#include<cstring>#include<algorithm>#define inf 0x3f3f3f3f#define eps 1e-8#define ls l,mid,rt<<1#define rs mid+1,rt,rt<<1|1#define LL __long long 64#define ll long long#include<cmath>#include<set>#define mod 997using namespace std;struct node{    int u,v,w;    bool operator < (const node &b)const {        return w > b.w;    }}q[1000000];__int64 cnt;int father[1000000];bool vis[100000];int fi(int r){    return r == father[r]? r: father[r] = fi(father[r]);}void mer(int a,int b,int c){    int x = fi(a);    int y = fi(b);    if(x != y){        if(!vis[x]&&!vis[y]){            father[x] = y;            cnt += c;        }        else if(!vis[x]||!vis[y]){//注意不要写成vis[x]||vis[y]            father[x]  = y;            cnt += c;            vis[x] = vis[y] = true;        }    }    else{        if(!vis[x]&&!vis[y]){            cnt += c;            vis[x] = vis[y] = true;        }    }}int main(){    int n,m,k,i,j,a,b,c;    while(~scanf("%d%d",&n,&m)){        if(!n&&!m) break;cnt = 0;        memset(vis,false,sizeof(vis));        for(i = 0;i < m;++ i){            scanf("%d%d%d",&a,&b,&c);            q[i].u = a,q[i].v = b;q[i].w = c;        }        sort(q,q+m);        for(i = 0;i < n;++ i){            father[i] = i;        }        for(i = 0;i < m ;++ i){            mer(q[i].u,q[i].v,q[i].w);        }        printf("%I64d\n",cnt);    }    return 0;}
0 0
原创粉丝点击