标签:c++
题目链接:
题意:
给出一些字符串,问能否将这些字符串 按照 词语接龙,首尾相接 的规则 使得每个字符串出现一次
如果可以 按字典序输出这个字符串序列
解题思路:
1.将每个字符串的首尾单词理解为图中的点,将字符串理解为边构图
2根据入度出度判断是否能构成欧拉路径
3并查集判断连通性
4将所有字符串按字典序排序可以使用sort排序
5欧拉路径的输出 用到fluery算法的思想:
设G 为一无向欧拉图,求G 中一条欧拉回路的算法为:
1) 任取G 中一顶点v0,令P0 = v0;
2) 假设沿Pi = v0e1v1e2v2 …eivi 走到顶点vi,按下面方法从E(G) - { e1, e2, …, ei }中选ei+1:
a) ei+1 与vi 相关联;
b) 除非无别的边可供选择,否则ei+1 不应该是Gi = G - { e1, e2, …, ei }中的桥。
3) 当2)不能再进行时算法停止。
可以证明的是,当算法停止时,所得到的简单回路Pm = v0e1v1e2v2 …emvm, (vm = v0)为G 中一条
欧拉回路。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #define M 1050 using namespace std; int n,top; struct edge{ int to,vis,id; }; vector<edge>w[M]; string str[M]; int ans[M]; int fa[29]; int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } void fleury(int loc) { for(int i=0; i<w[loc].size(); i++) if(!w[loc][i].vis) { w[loc][i].vis=1; fleury(w[loc][i].to); ans[top++]=w[loc][i].id; } return; } int main() { int indegree[28],outdegree[28]; int T; scanf("%d",&T); while(T--) { top=0; for(int i=0; i<26; i++) { w[i].clear(); outdegree[i]=indegree[i]=0; fa[i]=i; } scanf("%d",&n); int a,b; for(int i=0; i<n; i++) cin>>str[i]; sort(str,str+n); //根据字典序排序 int start; for(int i=0; i<n; i++) { a=str[i][0]-'a'; b=str[i][str[i].size()-1]-'a'; indegree[a]++; outdegree[b]++; fa[find(a)]=find(b); w[a].push_back((edge){b,0,i}); if(i==0) //重要 起点必须为初始化为第一条边的出节点(字典序最小,且满足 欧拉回路 的的要求) start=a; } int ss=0,num=0,start_num=0,end_num=0; for(int i=0; i<26; i++) { if((indegree[i]||outdegree[i])&&find(i)==i) ss++; if(indegree[i]!=outdegree[i]) { if(outdegree[i]-indegree[i]==-1) start=i,start_num++; else if(outdegree[i]-indegree[i]==1) end_num++; num++; } } if((num==0||(num==2&&start_num==1&&end_num==1))&&ss==1) { fleury(start); for(int i=top-1;i>=0;i--) { if(i==0) cout<<str[ans[i]]<<endl; else cout<<str[ans[i]]<<"."; } } else cout<<"***"<<endl; } return 0; }
标签:c++
原文地址:http://blog.csdn.net/axuan_k/article/details/45844491