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

 

原文地址:https://www.cnblogs.com/cchun/p/2520118.html