题意:输入N个单词,N < 100000,是否可以把所有这些单词排成一列,使得每个单词的第一个字母和最后一个字母相同。每个单词最多有1000个字母,输入可能有重复的单词。
思路:
1、把字母当成结点,单词看做有向边,问题有解当且仅当图中存在欧拉回路。有向图判断存在欧拉回路的条件有两个:(1)把图看做无向图,图是连通的(DFS访问,若存在未访问的,则是不连通的) ;(2)最多有两个点入度不等于出度,其中一个是起点,一个是终点。
2、每行输入的数据只需记录首字母和最后一个字母,然后转化为数字,因此数组只需开到26记录26个字母对应的数字即可。
代码如下:
#include<cstdio>
#include<cstring>
const int maxn = 1000 + 10;
int G[27][27],in[27],out[27],N,num[27];
void read() //读入数据
{
memset(G,0,sizeof(G));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
scanf("%d",&N);
char s[maxn];
int first,last;
while(N--)
{
scanf("%s",s);
first = s[0] - 'a';
last = s[strlen(s)-1] - 'a';
G[first][last]++;
in[last]++;
out[first]++;
}
}
void dfs(int i)
{
num[i] = 1;
for(int j = 0;j < 26;j++)
{
if((G[i][j] > 0 || G[j][i] > 0) && num[j] == 0)
{
dfs(j);
}
}
return;
}
bool judge_connect() //判断连通性
{
memset(num,0,sizeof(num));//存储访问情况
for(int i = 0;i < 26;i++)
{
if(out[i] > 0)
{
dfs(i);
break;
}
}
for(int i = 0;i < 26;i++)
{
if((in[i] > 0 || out[i] > 0) && num[i] == 0)
{
return false;
}
}
return true;
}
bool judge_deg() //判断度数情况
{
int i,start = 0,end = 0;
for(i = 0;i < 26;i++)
{
if(in[i] != out[i])
{
if(in[i] == out[i] + 1) end++;
else if(out[i] = in[i] + 1) start++;
else
{
return false;
}
}
if(end > 1 || start > 1)
{
return false;
}
}
if(start + end > 2)
{
return false;
}
return true;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
read();
if(judge_connect() && judge_deg())
{
printf("Ordering is possible.\n");
}
else
{
printf("The door cannot be opened.\n");
}
}
}