题目描述
有 N 个盘子,每个盘子上写着一个仅由小写字母组成的英文单词。你需要给这些盘子安排一个合适的顺序,使得相邻两个盘子中,前一个盘子上单词的末字母等于后一个盘子上单词的首字母。请你编写一个程序,判断是否能达到这一要求。如果能,请给出一个合适的顺序。
输入描述
多组数据。第一行给出数据组数T,每组数据第一行给出盘子数量N,接下去N行给出小写字母字符串,一种字符串可能出现多次。
输出描述
若存在一组合法解输出“Ordering is possible.”,否则输出“The door cannot be opened.”。
样例输入
3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok
样例输出
The door cannot be opened.
Ordering is possible.
The door cannot be opened.
时间限制、数据范围及描述
时间:1s 空间:64M
1<=N<=10^5;
|S|<=1000
思路:
每一个单词有用的信息只有首尾两个字母,那么建一张图令节点表示小写字母;边表示一种单词的转移。问题就变成了在图中判断欧拉路径的存在性。
若有向图G存在欧拉路径(即为半欧拉图),那么当且仅当G的基图联通且存在顶点uu的入度比出度大1,vv的入度比出度小1,其他所有顶点的入度等于出度。
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=1050,M=50; int T,n,m; char s[N]; int cnt,cnt1,cnt2; int fa[M],u[M],v[M]; int find(int x) { if(fa[x]==x) return x; return fa[x]=find(fa[x]); } int main() { scanf("%d",&T); while (T--) { memset(u,0,sizeof u); memset(v,0,sizeof v); scanf("%d",&n); cnt=cnt1=cnt2=0; for(int i=1; i<=30; i++) fa[i]=i; for(int i=1; i<=n; i++) { scanf("%s",s+1); m=strlen(s+1); int l=s[1]-‘a‘+1,r=s[m]-‘a‘+1; fa[find(l)]=find(r); u[l]++; v[r]++; } for(int i=1; i<=26; i++) if(((u[i]||v[i])&&(find(i)==i))||abs(u[i]-v[i]) > 1) cnt++; if(cnt>1) { puts("The door cannot be opened."); continue; } for(int i=1; i<=26; i++) if(u[i]>v[i]) cnt1++; else if(u[i]<v[i]) cnt2++; if(cnt1!=cnt2||cnt1>1) puts("The door cannot be opened."); else puts("Ordering is possible."); } return 0; }
原文:https://www.cnblogs.com/mysh/p/11333678.html