并查集的反思-----小希的迷宫与Is It a Tree?
2013-04-01 17:32
316 查看
/* 事实证明半斤八两的理解忘记的速度会很快,今天早上起来忽然想起来这个题(因为昨天碰到一个欧拉回路+并查集+字典树),已然思路不清晰了。 是什么什么让我认识并查集的呢?是Hdu的畅通工程,给出一些列已经连通的点,要你判断还需要多少建多少条路使保持畅通。我们解决的办法是将能够保持连通转化为所有的点位于一个集合,并且将他们的祖先序号规定为最小元素的值。然后还需要建的路即是不相交的集合。然后我们又可以做这样一类题,图是否连通,这类题,最小生成树也可以做。而小希的迷宫呢?小希的迷宫是在保持原有图形连通的基础上加入了一个新的条件---不成环。在思考不成环这个问题时,我注意到了原来一直没有透彻理解的问题---路径压缩。如果合并的两个点具有公共祖先,那么将形成以个环。然后,又碰到了这道经典的题目,is it a tree?这个图在小希的迷宫上又增加了一个条件---有向图,很自然不可能由一个节点的子孙走回父亲节点,所以判断入度为1的条件---即不走回头路 find(i)=i. 并查集目前为止一般包括三个函数 void union()//跟据你的输入合并2个点 int find()//寻找祖先+路径压缩 void make()//初始化 无向图的并查集 1.不成回路 2.联通 */ #include<stdio.h> #include<string.h> #define maxn 100002 #define max(a,b) (a)>(b)?(a):(b) int flag[100001]; int bin[100001]; int ans; int Find(int x) { while(bin[x]!=x) x=bin[x]; return x; } void Union(int x,int y) { flag[x]=flag[y]=1; x=Find(x); y=Find(y); if(x!=y) bin[x]=y; else ans=0;//如果祖先相同,则构成回路。太重要了。 } int main() { int a,b,i; while(scanf("%d%d",&a,&b)!=EOF &&(a!=-1 || b!=-1)) { memset(flag,0,sizeof(flag)); int count=0; if(a==0 && b==0) { printf("Yes\n"); continue; } for(i=0;i<=100001;i++) bin[i]=i; //bin[i]=maxn; //bin[a]=a; //bin[b]=b; Union(a,b); ans=1; while(scanf("%d%d",&a,&b),a,b) { //bin[a]=a; //bin[b]=b; Union(a,b); } for(i=1;i<=100001;i++) if(flag[i]&&bin[i]==i) count++; if(count>1) ans=0;//这个判断是否联通。 if(ans) printf("Yes\n"); else printf("No\n"); } return 0; }
hdu 1325
/* 并查集 题意:输入每两个数a,b, a指向b(即:a为b的父亲),输入0,0代表一棵树结束; 思路:判断是否为树; 1、空树是一棵树 2、除了根节点,每个节点入度必须为1 3、不能有圈 4、不能有连通分量 */ #include<stdio.h> #define N 10005 int father ,mark ; void MakeSet()//初始化 { for(int i=0;i<N;i++) {father[i]=i; mark[i]=0;} } int FindSet(int x) { if(x!=father[x]) father[x]=FindSet(father[x]);//没有路径压缩实践证明超时 return father[x]; } bool Union(int a,int b) { int x=FindSet(a); int y=FindSet(b); if(x==y) return false; else father[y]=x;//被卡了,注意接的顺序 return true; } int main() { int s,e; int can=1; while(scanf("%d%d",&s,&e),s>=0&&e>=0) { MakeSet(); Union(s,e); bool judge=true; if(s==0&&e==0)//空树也满足条件 { printf( "Case %d is a tree.\n",can++); continue; } mark[s] = mark[e] = 1; while(scanf("%d%d",&s,&e),s||e) { mark[s]=mark[e]=1; if(FindSet(e)==e)//判断节点入度是否为1 { judge*=Union(s,e);//判断是否有圈 } else judge=false; } int flag=0; for(int i=0;i<N;i++) { if(mark[i]) { if(FindSet(i)==i) flag++; } } if(flag==1&&judge) printf( "Case %d is a tree.\n",can++); else printf( "Case %d is not a tree.\n",can++); } return 0; }
相关文章推荐
- HDU 1272 小希的迷宫 + 1325 Is It A Tree? , 并查集
- HDU1272&&POJ1308 小希的迷宫&&Is It A Tree?(并查集)
- 杭电 hdu 1272 小希的迷宫 和 hdu 1325 Is It A Tree?(最下生成树 + 并查集)
- HDU 1272小希的迷宫 1325Is It A Tree? 并查集确定图为树
- Is it a tree?(和上一道小希的迷宫相同)
- 并查集之判断图是否成环—小希的迷宫and is it a tree
- poj 1308 is it a tree?(图的性质||基础并查集) (同hdu 1272 小希的迷宫 )
- ACM-并查集之小希的迷宫——hdu1272
- 【HDU1272】小希的迷宫(并查集)
- hdu1272 - 小希的迷宫 (基础并查集)
- HDU 1272 小希的迷宫(并查集)
- 小鑫的城堡(参考的小希的迷宫写的代码)并查集
- hdu 1272 小希的迷宫 (并查集)
- HDU - 1272 小希的迷宫 并查集集合数判断
- HDU-1272 小希的迷宫(并查集)
- HDU-1272-小希的迷宫(并查集)
- hdu1272 小希的迷宫 (并查集)
- HDU 1272 小希的迷宫(并查集)
- 小希的迷宫(并查集)
- HDOJ 1272 小希的迷宫 (并查集实现 及 Tarjan实现)