题目大意:给你N个单词,首位单词相接,每个单词限用一次。问能不能全部连接起来。
思路:可以把单词的首尾的单词看成点,把单词看成路。而且要确定这个图是否联通。然后判断每个点的入度与出度是不是相等或者等于一。因为有向图的欧拉回路存在的判断:每个节点的入度都等于出度,起点终点的出入度可以差一。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int set[100050];
int map[27][27];
int in[27];
int out[27];
int v[27];
int Abs(int x)
{
return x>0?x:-x;
}
void Init(int n)
{
for(int i=0;i<n;i++)
set[i]=i;
}
int find(int x)
{
int i,j,r = x;
while (set[r] != r)
r = set[r];
i = x;
while (i != r)
{
j = set[i];
set[i] = r;
i = j;
}
return r;
}
bool merge(int a,int b)
{
int x=find(a);
int y=find(b);
if(x==y)
return false;
set[x]=y;
return true;
}
int main()
{
int T;
int i;
scanf("%d",&T);
while(T--)
{
int flag=1;
Init(26);
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(v,0,sizeof(v));
int n;
char str[2005];
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%s",&str);
int st=str[0]-'a';
int en=str[strlen(str)-1]-'a';
in[st]++;
out[en]++;
v[st]=v[en]=1;
merge(st,en);
}
int s=0;
for(i=0;i<26;i++)
if(v[i] && set[i]==i)s++;
if(s>1){flag=0;printf("The door cannot be opened.\n");continue;}
s=0;
for(i=0;i<26;i++)
{
if(Abs(out[i]-in[i])>1){flag=0;printf("The door cannot be opened.\n");break;}
else if(Abs(out[i]-in[i])==1)s++;
}
if((s==0 || s==2 )&& flag==1)printf("Ordering is possible.\n");
}
return 0;
}