http://zh.wikipedia.org/wiki/%E4%B8%80%E7%AC%94%E7%94%BB%E9%97%AE%E9%A2%98
对于一个给定的连通图,通过图(无向图或有向图)中所有边一次且仅一次行遍图中所有顶点的通路称为欧拉通路,通过图中所有边一次并且仅一次行遍所有顶点的回路称为欧拉回路。具有欧拉回路的图称为欧拉图,具有欧拉通路而无欧拉回路的图称为半欧拉图。
连通的无向图 是欧拉环的充要条件是:中每个顶点没有奇顶点。
证明:
连通无向图有欧拉路径的充要条件也可以写作“图中奇顶点数目不多于2个”,这是因为奇顶点数目不可能是1个。实际上,连通无向图中,奇顶点的数目总是偶数。对于不连通的无向图,如果有两个互不连通的部分都包含不止一条边,那么显然不能一笔画。只有当此图的边全都在某一个连通部分中即其它的连通部分都是一个个孤立的顶点,度数为0),并满足连通无向图关于一笔画的充要条件,而该图才能一笔画。也即是说,可以一笔画的(无向)图如果不是连通图,就必定是一个可以一笔画的连通图与若干个孤立顶点的组合。
除了用顶点的度数作为判定的充要条件,还可以用图中边的特性来作为欧拉回路存在的判定准则。连通的无向图 中存在欧拉回路,等价于图所有的边可以划分为若干个环的不交并。具体来说,等价于存在一系列的环,使得图里的每一条边都恰好属于某一个环。
证明:将这 个奇顶点分成 对後分别连起,则得到一个无奇顶点的连通图。由上知这个图是一个环,因此去掉新加的边後至多成为 条欧拉路径,因此必然可以用 笔画成。但是假设全图可以分为 条欧拉路径,则由定理一知,每条链中只有不多于两个奇顶点,于是 。因此必定要 笔画成。
#include <stdio.h> #include <string.h> #include <stdlib.h> int f[30],num[30],in[30],out[30];//分别用于并查集,入度,出度 void init() { int i; for( i=0; i<26; i++) { f[i]=i; num[i]=1; } memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); } int findSet(int n) { if(f[n]!=n) f[n]=findSet(f[n]); return f[n]; } void unionSet(int m,int n) { int p=findSet(m),q=findSet(n); if(p==q) return; if(num[p]>num[q]) { f[q]=p; num[p]+=num[q]; } else { f[p]=q; num[q]+=num[p]; } } int main() { int nCase,n,i,t1,t2; char s[1005]; scanf("%d",&nCase); while(nCase--) { scanf("%d",&n); init(); for(i=0; i<n; i++) { scanf("%s",s); t1=s[0]-'a',t2=s[strlen(s)-1]-'a'; out[t1]++; in[t2]++; unionSet(t1,t2); } int flag1=1,flag2=1,flag3=1; for(i=0; i<26; i++) { if((out[i]||in[i])&&(f[i]!=f[t1])) { flag1=0; break; } } if(!flag1) { puts("The door cannot be opened."); continue; } int u=0,v=0; for(i=0; i<26; i++) { if(out[i]!=in[i]) { t1=out[i]-in[i]; if(t1==1) { u++; } else if(t1==-1) { v++; } else { flag3=0; break; } } } if(!flag3) { puts("The door cannot be opened."); continue; } if((u+v==0)||(u==1&&v==1)) puts("Ordering is possible."); } }