发发牢骚:
刚刚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; }
|