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 或两个点的入度=出度)

 

注意当所以结点的出入度都相等时为欧拉图。

 

 

View Code
  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 */

 

posted @ 2012-08-26 16:16  另Ⅰ中Feel▂  阅读(218)  评论(0编辑  收藏  举报