hunnu 11106 pseudoforest 图论

来源:互联网 发布:足贴的有用么 知乎 编辑:程序博客网 时间:2024/06/05 05:30
HDU3367_Pseudoforest_伪森林_最大生成树
2012-03-24 22:01

题目大意:

              给定一个图,可能有连通分量,然后要求求这个图的最大伪森林,并规定伪森林就是一个图中的每一个连通分量最多只含有一个圈。

解题思路:

            按照kruscal算法的思想,先对所有边排序,然后进行合并:

            有两种情况:

            1、如果这时候查找到的两个顶点有公共父节点,然后这一连通块中没有圈,那么就把它加上去,然后这个块标志为有圈。

             2、如果查找的两个顶点分别在两个不同的连通分量,那么如果两个连通分量不都有圈,就进行合并。

                        1'如果两个连通分量都没有圈,那么合并之后的连通块标志为无圈。

                         2'如果两个连通分量有一个有圈,那么合并之后的连通块标志为有圈。

             由于要求的是最大森林,并且边已经按从大到小排序,所以只要把所有满足的边都塞上去,结果就是最优。

这里的并查集加秩跟不加秩的时间复杂度是一样的,可能数据量太小,没有体现优势。



#include<stdio.h>#include<algorithm>using namespace std;const int N=100001;int f[N],r[N];struct node{    int u,v,c;    void input()    {        scanf("%d%d%d",&u,&v,&c);    }}st[N];bool cmp(node a,node b){    return a.c>b.c;}int getF(int i){    while(i!=f[i])        i=f[i];    return i;}int main(){    int n,m,i,res,x,y;    while(scanf("%d%d",&n,&m)==2&&n)    {        for(i=0;i<=n;++i)        {            r[i]=0;            f[i]=i;        }        for(i=0;i<m;++i)            st[i].input();        sort(st,st+m,cmp);        res=0;        for(i=0;i<m;++i)        {            x=getF(st[i].u);            y=getF(st[i].v);            if(x!=y)            {                res+=st[i].c;                if(r[x]<r[y])                    f[x]=y;                else                {                    f[y]=x;                    if(r[x]==r[y])                        r[x]++;                }            }            else if(x!=getF(n))            {                f[x]=n;                res+=st[i].c;            }        }        printf("%d\n",res);    }    return 0;}/*当生成圈的时候就和n挂在一起,当新加两个点,其祖先都和n在一个圈中时,说明这两个点所在集合分别包含有圈,应当舍弃。*/


原创粉丝点击