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 }