题意 有 $N$ 个盘子,每个盘子上写着一个仅由小写字母组成的英文单词。你需要给这些盘子安排一个合适的顺序,使得相邻两个盘子中,前一个盘子上单词的末字母等于后一个盘子上单词的首字母。请你编写一个程序,判断是否能达到这一要求。如果能,请给出一个合适的顺序。 多组数据。第一行给出数据组数 $T$,每组数据第一行给出盘子数量 $N$,接下去 $N$ 行给出小写字母字符串,一种字符串可能出现多次。 若存在一组合法解输出Ordering is possible.,否则输出 The door cannot be opened.。
思路 很明显就是寻找有没有半 欧拉图。 先来看一看半 欧拉图的定义:
有向图G为半欧拉图,当且仅当G为连通图,且存在顶点u的入度比出度大1,v的入度比出度小1,其它所有顶点的入度等于出度。 存在欧拉路径而不存在欧拉回路。
再来看一看有向图的半 欧拉图的性质: 1.图G是连通的,不能有孤立的点存在。 2.存在两个顶点,其入度不等于出度,其中一点出度比入度大1,为路径起点,另一点入度比出度大1,为路径的终点。 好了,有了这些信息,那么这道题就很好打了。 可以采用并查集来帮助check是否为半欧拉图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #include <algorithm> #include <bitset> #include <complex> #include <deque> #include <exception> #include <fstream> #include <functional> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <iterator> #include <limits> #include <list> #include <locale> #include <map> #include <memory> #include <new> #include <numeric> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stack> #include <stdexcept> #include <streambuf> #include <string> #include <typeinfo> #include <utility> #include <valarray> #include <vector> #include <cstring> using namespace std;#define MAXE 400010 inline int read () { char ch=getchar ();int res=0 ,f=1 ; while (ch<'0' ch>'9' ){if (ch=='-' ) f=-1 ;ch=getchar ();} while (ch>='0' &&ch<='9' ) res=res*10 +ch-'0' ,ch=getchar (); return res*f; } int type,n,m;int in[MAXE],out[MAXE],fa[MAXE];bool vis[MAXE];int T;char as[1010 ];int getfa (int x) { return x==fa[x]?x:fa[x]=getfa (fa[x]); } int main () { T=read (); while (T--){ int Fans=0 ; n=read ();m=n; memset (in,0 ,sizeof (in)); memset (out,0 ,sizeof (out)); for (int i=1 ;i<=26 ;i++) fa[i]=i; for (int i=1 ;i<=n;i++){ int x,y; cin>>as; x=as[0 ]-'a' +1 ,y=as[strlen (as)-1 ]-'a' +1 ; fa[getfa (y)]=getfa (x); in[y]++;out[x]++; } int ans=0 ; for (int i=1 ;i<=26 ;i++){ if (((in[i]!=0 out[i]!=0 )&&(getfa (i)==i))abs (in[i]-out[i])>1 ) ans++; } if (ans>=2 ){puts ("The door cannot be opened." );continue ;} int ans1=0 ,ans2=0 ; for (int i=1 ;i<=26 ;i++) (in[i]>out[i]?ans1++:(in[i]<out[i]?ans2++:ans)); if (ans1!=ans2ans1>1 ) puts ("The door cannot be opened." ); else puts ("Ordering is possible." ); } return 0 ; }