判断欧拉路径是否存在及求出字典序最小的欧拉路径问题(如果存在)。
将字符串的第一个字母和最后一个字母间连边,将字母看成点,最多可能有26个点(a-z),如果有欧拉路径,还要判断是否有欧拉回路,如果有,则需要找一个字典序最小的点开始生成这条链,否则以起点开始生成链,起点即为出度比入度大1的点。
欧拉路径是否存在的判定:
1.全部点在一个联通块 ----用并查集判联通块的数量
2.所有点出度入度相等 ----in[],out[]记录出度与入度
3.或者有一个出度比入度小1,另一个出度比入度大1(源点与汇点)
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <string> #define Mod 1000000007 using namespace std; #define N 2007 string ss[N]; struct node { int u,v,next; string w; }G[N]; int first[28],fa[28],in[28],out[28],vis[28]; int tot,k,start; int evis[N]; string ans[N]; void init() { int i; for(i=0;i<28;i++) fa[i] = i; tot = 1; memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); for(i=0;i<=2000;i++) { G[i].u = G[i].v = G[i].next = 0; G[i].w = ""; } memset(first,-1,sizeof(first)); memset(vis,0,sizeof(vis)); memset(evis,0,sizeof(evis)); for(int j=0;j<=2000;j++) ans[j] = ""; } int findset(int x) { if(x != fa[x]) fa[x] = findset(fa[x]); return fa[x]; } int cmp(string ka,string kb) { return ka>kb; } void addedge(int u,int v,string w) { G[tot].u = u; G[tot].v = v; G[tot].w = w; G[tot].next = first[u]; first[u] = tot++; out[u]++; in[v]++; vis[u] = vis[v] = 1; int fx = findset(u); int fy = findset(v); if(fx != fy) fa[fx] = fy; } int Euler_Path() { int block = 0,i; int O = 0; int I = 0; start = -1; for(i=0;i<26;i++) { if(vis[i]) //涉及到的字母 { int fk = findset(i); if(fk == i) block++; if(block > 1) return false; if(in[i] == out[i]+1) //入大出,奇度数点 I++; else if(in[i]+1 == out[i]) //出大入,奇度数点 O++,start = i; else if(in[i] != out[i]) return false; } } if(block != 1) return false; if((O == I && O == 1) || (O == I && O == 0)) //没有奇度数点或者只有源点和汇点是奇度数点 { if(start == -1) //没有找到起点,是欧拉回路 { for(i=0;i<26;i++) { if(vis[i] && out[i] > 0) //找字典序最小的字母做起点 { start = i; return true; } } } //如果已找到起点,则不能是欧拉回路 if(O == I && O == 1) return true; return false; } return false; } void dfs(int v,int flag) { for(int e=first[v];e!=-1;e=G[e].next) { if(!evis[e]) //边没被访问 { evis[e] = 1; dfs(G[e].v,e); } } if(flag != -1) ans[k++] = G[flag].w; } int main() { int t,i,j,n; scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(i=1;i<=n;i++) cin>>ss[i]; sort(ss+1,ss+n+1,cmp); //qsort(ss+1,n,28,cmp); for(i=1;i<=n;i++) { int u = ss[i][0]-'a'; int v = ss[i][ss[i].length()-1]-'a'; addedge(u,v,ss[i]); } if(Euler_Path()) { k = 0; dfs(start,-1); cout<<ans[k-1]; for(i=k-2;i>=0;i--) cout<<"."<<ans[i]; printf("\n"); } else puts("***"); } return 0; }