NYOJ 99 POJ 2337

View Code
  1 /*
  2 1.先用并差集判断图是否连通 
  3 2.判断是否存在欧拉路或欧拉回路
  4 3.DFS求欧拉路径 
  5 */ 
  6 #include<iostream>
  7 #include<cstdio>
  8 #include<cstring>
  9 #include<algorithm>
 10 using namespace std;
 11 
 12 const int size = 1005;
 13 
 14 struct nodedge
 15 {
 16    int e;//单词的最后一个字母  对应的数字 相当于:路径的末端 
 17    int id;//记录这个单词是第几个单词 
 18    int next;//首字母相同的单词连起来 
 19    bool vis;//标志这个单词是否用过 
 20 }edge[size];
 21 
 22 struct nodechar
 23 {
 24   char ch[32];//存放单词 
 25 }cha[size];
 26 
 27 int degree[27];//计算出现的 字母的 初度入度 
 28 int father[27];//并差集 
 29 int rank[27];
 30 bool show[27];
 31 int stack[size]; //存放欧拉路径 
 32 int k[27];// k[i] 存放以 以  i 为首的字母链的所在位置  
 33 int st;//记录路径 stack[] 
 34 int point;//记录出现了几个字母 
 35 int M;
 36 
 37 int find(int x)//非递归压缩路径 
 38 {
 39    int i=x;
 40    while(i!=father[i])
 41      i=father[i];
 42    int j=x;
 43    while(j!=i)
 44     {
 45       int k= father[j];
 46       father[j]=i;
 47       j=k;
 48     }
 49    return i;
 50 }
 51 
 52 void uion(int x,int y)//并差集 合并两个子集 
 53 {
 54    x=find(x);
 55    y=find(y);
 56    if(x!=y)
 57     {
 58       if(rank[x]>=rank[y])
 59        {
 60          rank[x]+=rank[y];
 61          father[y]=x;
 62        }
 63       else 
 64       {
 65         rank[y]+=rank[x];
 66         father[x]=y;
 67       }
 68     }
 69 }
 70 
 71 bool cmp(nodechar x,nodechar y)
 72 {
 73    return strcmp(x.ch,y.ch)>0; 
 74 } 
 75 
 76 void init()
 77 {
 78    int i,len;
 79    for(i=0;i<26;++i)
 80     {
 81       degree[i]=0;
 82       father[i]=i;
 83       rank[i]=1;
 84       show[i]=false;
 85       k[i]=-1;
 86     }
 87    st=0;
 88    point=0;
 89    
 90    for(i=0;i<M;++i)
 91     scanf("%s",cha[i].ch);
 92     
 93    sort(cha,cha+M,cmp);//从 大  到  小 排序 (插入到之后得到的是从小大排序) 
 94    for(i=0;i<M;++i)
 95     printf("%s\n",cha[i].ch); 
 96    
 97    for(i=0;i<M;++i)
 98     {
 99        len=strlen(cha[i].ch);
100        int h1 = cha[i].ch[0]-'a';
101        int h2 = cha[i].ch[len-1]-'a';
102        
103        edge[i].e=h2;//依次插入之后 变成从  小到大排序 
104        edge[i].id=i;
105        edge[i].vis=false;
106        edge[i].next=k[h1];
107        k[h1]=i;
108        degree[h1]--;//注意这里设计的 
109        degree[h2]++;
110        if(!show[h1]){show[h1]=true;point++;}
111        if(!show[h2]){show[h2]=true;point++;}
112        uion(h1,h2);
113     }
114     for(i=0;i<26;++i)
115      if(show[i])find(i);
116 }
117 
118 int start()
119 {
120     int odd=0,t1,t2;//t1,t2记录两个奇数度结点的位置 
121     int i;
122 
123     for(i=0;i<26;++i)  
124      if(show[i])
125       {
126         if(rank[father[i]]!=point)return -1;
127         if(!degree[i])continue;
128         if(degree[i]>1 || degree[i]<-1)return -1;//少了这个条件就错了 (也即可能有  odd==2,奇数的出度,或入度不是 1,或-1) 
129         if(0==odd)t1=i;
130         if(1==odd)t2=i;
131         odd++;
132       }
133 
134      if(odd==1 || odd>2 || (degree[t1]+degree[t2]))return -1;//第三个条件限制一个入度为 1 ,一个出度为1 
135      if(odd==2)//存在欧拉路 
136       {
137         if(degree[t1]==-1)return t1;
138         else return t2;
139       }
140      if(odd==0)//存在欧拉回路
141       {
142         for(i=0;i<26;++i)
143          if(show[i])return i;
144       } 
145      return -1;
146 }
147 
148 void dfs(int t)
149 {
150    int i;
151    for(i=k[t];i!=-1;i=edge[i].next)
152     {
153       if(edge[i].vis==0)
154        {
155          edge[i].vis=1;
156          dfs(edge[i].e);
157          stack[st++]=edge[i].id;//单词ID是以  单词的末尾字母存的 所以提取末尾获得单词ID 
158        }//同一个起点可能引出多条边 从这个点用一个单词(一条边)得到一个新的起点此时从新起点开始  
159     }//     以上从一个起点选边都是 选这个起点 最小的边(注意以上排序) 
160 }
161 
162 int main()
163 {
164    int i,iscase;
165    scanf("%d",&iscase);
166    while(iscase--)
167     {
168       scanf("%d",&M);
169       init();
170       int t=start();
171       if(-1==t)printf("***\n");
172       else
173        {
174           dfs(t);
175           printf("%s",cha[stack[st-1]].ch);
176           for(i=st-2; i>=0;--i)
177            printf(".%s",cha[stack[i]].ch);
178           printf("\n");              
179        }
180     }
181    return 0;
182 }

 

posted @ 2012-05-10 16:39  知行执行  阅读(288)  评论(0编辑  收藏  举报