//ver1:用树的性质:顶点数=边数+1,注意空树的情况 #include<cstdio> #include<cstring> int main() { int x,y,v,e,kase=0,n[100000]; while(1){ memset(n,0,sizeof n); v=e=0; while(scanf("%d%d",&x,&y)&&x&&x!=-1){ if(!n[x]) n[x]=1,v++; if(!n[y]) n[y]=1,v++; e++; } if(x<0) break; if(!v||v-1==e) printf("Case %d is a tree.\n",++kase); else printf("Case %d is not a tree.\n",++kase); } }*/
//ver2:并查集 #include<cstdio> #include<cstring> int p[100005],v[100005],flag,tot; //tot表示连通块总量,flag表示是否符合条件(0为符合) void init(){ //p[i]指向父亲,v[i]的正负表示i是否出现 for(int i=1;i<100005;i++) p[i]=i; memset(v,0,sizeof v); flag=tot=0; } int find(int x){ int f=x,r=x,t; while(p[f]!=f) //采用循环的方式避免爆栈(但据说这道题也不会爆栈...) f=p[f]; //先找到当前树的根节点 while(r!=f){ //结束后f就是当前树的根节点 t=p[r]; //再从下往上让每个结点指向f p[r]=f; r=t; } return f; } int main() { int x,y; while(1){ init(); while(scanf("%d%d",&x,&y)==2&&x&&x!=-1){ if(flag) continue; //如果已经不符合了,无视之... if(!v[x]) tot++; //如果出现新的结点,表示出现了一个新的连通块(初始就是自己) if(!v[y]) tot++; v[x]++,v[y]++; int px=find(x),py=find(y); if(px==py) flag=1; //如果当前要连接的结点已经在一个连通块,那么就会形成环路 else {p[px]=py,tot--;} //否则将两个已知连通块连通,连通块-1 } if(x<0) break; if(tot>1) flag=1; //若结束时连通块数目>1 if(!flag) printf("Yes\n"); else printf("No\n"); } }