HDU-1116-Play on Words (并查集+欧拉图)
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1116
程序分析:
词语接龙,问能不能全部接下去,其实就是欧拉图。
解决方法:
用欧拉图的知识点来判断是否存在欧拉图。
欧拉图:
通过图(无向图或有向图)中所有边一次且仅一次行遍图中所有顶点的通路称为欧拉通路,通过图中所有边一次且仅一次行遍所有顶点的回路称为欧拉回路。具有欧拉回路的图称为欧拉图(Euler Graph),具有欧拉通路而无欧拉回路的图称为半欧拉图。
1.无向连通图G是欧拉图,当且仅当G不含奇数度结点(G的所有结点度数为偶数);
2.无向连通图G含有欧拉通路,当且仅当G有零个或两个奇数度的结点;
3.有向连通图D是欧拉图,当且仅当该图为连通图且D中每个结点的入度=出度
4.有向连通图D含有欧拉通路,当且仅当该图为连通图且D中除两个结点外,其余每个结点的入度=出度,且此两点满足deg-(u)-deg+(v)=±1。(起始点s的入度=出度-1,结束点t的出度=入度-1 或两个点的入度=出度)
注意当所以结点的出入度都相等时为欧拉图。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 const int Max = 50; 6 int Far[Max]; 7 int In[Max]; 8 int Out[Max]; 9 int Sign[Max]; 10 int Used[Max]; 11 int Rank[Max]; 12 13 void Make_set(int n) 14 { 15 for(int i=0; i<n; i++) 16 { 17 Far[i] = i; 18 } 19 memset(Sign, 0, sizeof(Sign)); 20 memset(Used, 0, sizeof(Used)); 21 memset(In,0, sizeof(In)); 22 memset(Out,0, sizeof(Out)); 23 memset(Rank, 0, sizeof(Rank)); 24 } 25 26 /* 27 int Find(int x) 28 { 29 int i = 0; 30 while(Far[x] != x) 31 { 32 Sign[i++] = x; 33 x = Far[x]; 34 } 35 for(; i>=1; i--) 36 { 37 Far[Sign[i]] = x; 38 } 39 return x; 40 }*/ 41 42 int Find(int x) 43 { 44 if(Far[x] != x) 45 return Far[x]=Find(Far[x]); 46 return Far[x]; 47 } 48 49 void Unio(int a, int b) 50 { 51 a = Find(a); 52 b = Find(b); 53 if(a == b) 54 return ; 55 Far[a] = b; 56 } 57 58 int main() 59 { 60 //string s; 61 int a, b; 62 int t, n; 63 cin>>t; 64 while(t--) 65 { 66 Make_set(Max); 67 cin>>n; 68 for(int i=0; i<n; i++) 69 { 70 string s; //必须定义在里面,因为每一次输入前都要初始化s 71 cin>>s; 72 73 a = s[0]-'a'; 74 b = s[s.length()-1]-'a'; 75 Used[a] = Used[b] = 1; //标记为存在 76 //统计出入度 77 In[b]++; 78 Out[a]++; 79 //合并 80 Unio(a, b); 81 } 82 int ans=0; 83 int k=0; 84 for(int j=0; j<26; j++) 85 { 86 if(Used[j]==1 && Find(j)==j) //统计分支 87 ans++; 88 if(In[j] != Out[j]) //统计出入度不相等的结点 89 Rank[k++] = j; 90 } 91 if(k>2 || ans>1) //如果分支大于1或者出入度不同的结点大于2个就不存在欧拉通路 92 cout<<"The door cannot be opened."<<endl; 93 else if( (k==0) || (k==2) && ( In[Rank[0]]==Out[Rank[0]]-1 && Out[Rank[1]]==In[Rank[1]]-1 //一个出度等于入度-1,一个入度等于出度-1 94 || In[Rank[1]]==Out[Rank[1]]-1 && Out[Rank[0]]==In[Rank[0]]-1 ) ) //如果k为0 就表示所有结点的出入度都相等,就是为欧拉图 95 cout<<"Ordering is possible."<<endl; 96 else 97 cout<<"The door cannot be opened."<<endl; 98 } 99 return 0; 100 } 101 102 103 /* 104 105 3 106 2 107 acm 108 ibm 109 3 110 acm 111 malform 112 mouse 113 2 114 ok 115 ok 116 117 */