• HDU3018Ant Trip(欧拉回路+邻接表+并查集)


    发发牢骚:

           刚刚TLE了两次,晕菜。这个鸭梨就大了。怎么我前面的那个u1[]跟v1[]这两个数组开不够大,结果HDU报的是TLE。这个压力。。

           第一次做这种有连通分量的欧拉路,离散又还没看到那里。所以看大牛的思路了。

    题目意思:

             有一个团队的人要去逛小镇,这个镇是无向图,然后规定每条路只能走一次,且两个小镇之间只有一条小路。(就避免了多条路径的问题。)然后这个图有可能有连通分量,如果图有孤立点,那么这个点就忽略掉,(这个挺有用)。问要分为几组人马才能够把这个城市的小镇全部逛完。

    解题思路:(连通分量,粗俗地讲就是一个图的几个隔离的子图,每个子图为一个连通分量)

             这里有个公式:如果每个连通分量的节点的度为偶数,那么就可以一笔画,如果连通分量中的节点的度为奇数点个数除以2;由于题目的数据量有滴滴微大,节点数100000,边数200000;所以这里要用邻接表做,然后要算每一个连通分量,就要用到并查集了。这里的并查集跟上面那条算一笔画结合得挺巧妙。

    代码:

    #include<iostream> 
    using namespace std; 
     
    const int MAX=100006;  
    struct point 

        int f,count,du,rank; 
    }p[MAX]; 
    int u1[2*MAX],v1[2*MAX],nv; 
     
    int find_set(int u)//查询 

        int v=u,t; 
        while(v!=p[v].f) 
        { 
            v=p[v].f; 
        } 
        while(u!=v)//压缩路径 
        { 
            t=p[u].f; 
            p[u].f=v; 
            u=t; 
        } 
        return v; 

     
    void union_set(int f1,int f2)//合并 

        f1=find_set(f1); 
        f2=find_set(f2); 
        if(f1==f2) 
            return ; 
        if(p[f1].rank>=p[f2].rank) 
        { 
            p[f2].f=f1; 
            if(p[f1].rank==p[f2].rank) 
            { 
                p[f1].rank++; 
            } 
            p[f1].count+=p[f2].count; 
        } 
        else 
        { 
            p[f1].f=f2; 
            p[f2].count+=p[f1].count; 
        } 

     
    void init() 

        for(int i=1;i<MAX;i++) 
        { 
            p[i].du=0
            p[i].f=i; 
            p[i].count=0
            p[i].rank=0
            u1[i]=0,v1[i]=0
        } 

     
    int main(void

        int i,ne,count; 
        while(scanf("%d%d",&nv,&ne)==2)//点,边 
        { 
            init(); 
            for(i=1;i<=ne;i++) 
            { 
                scanf("%d%d",&u1[i],&v1[i]); 
                p[u1[i]].du++; 
                p[v1[i]].du++; 
            } 
            //下面这个算节点的度的奇偶个数,要放在union_set前 
            for(i=1;i<=nv;i++) 
            { 
                if(p[i].du%2==1
                { 
                    p[i].count=1
                } 
            } 
            for(i=1;i<=ne;i++) 

                union_set(u1[i],v1[i]); 
     
            count=0
            for(i=1;i<=nv;i++) 
            { 
                if(p[i].f==i&&p[i].du!=0)//p[i].du==0的,那么这个店就是孤立的,去掉 
                { 
                    if(p[i].count==0)//奇数度是1,偶数度是0 
                        count++; 
                    else 
                    { 
                        count+=p[i].count/2
                    } 
                }             
            } 
            printf("%d\n",count); 
        } 
        return 0

     

  • 相关阅读:
    《课后习题》
    《课后习题---求两点之间的距离》
    《day06---面向对象入门》
    《java作业》
    《选择排序》
    《冒泡排序》
    《java版进制转换》
    《c语言全局变量的用法》
    《递归问题_2》
    C#把动态创建的多个控件中指定控件显示在最上层
  • 原文地址:https://www.cnblogs.com/cchun/p/2520118.html
Copyright © 2020-2023  润新知