Description
Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us.
There is a large number of magnetic plates on every door. Every plate has one word written on it. The plates must be arranged into a sequence in such a way that every word begins with the same letter as the previous word ends. For example, the word ``acm'' can be followed by the word ``motorola''. Your task is to write a computer program that will read the list of words and determine whether it is possible to arrange all of the plates in a sequence (according to the given rule) and consequently to open the door.
There is a large number of magnetic plates on every door. Every plate has one word written on it. The plates must be arranged into a sequence in such a way that every word begins with the same letter as the previous word ends. For example, the word ``acm'' can be followed by the word ``motorola''. Your task is to write a computer program that will read the list of words and determine whether it is possible to arrange all of the plates in a sequence (according to the given rule) and consequently to open the door.
Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing a single integer number Nthat indicates the number of plates (1 <= N <= 100000). Then exactly Nlines follow, each containing a single word. Each word contains at least two and at most 1000 lowercase characters, that means only letters 'a' through 'z' will appear in the word. The same word may appear several times in the list.
Output
Your program has to determine whether it is possible to arrange all the plates in a sequence such that the first letter of each word is equal to the last letter of the previous word. All the plates from the list must be used, each exactly once. The words mentioned several times must be used that number of times.
If there exists such an ordering of plates, your program should print the sentence "Ordering is possible.". Otherwise, output the sentence "The door cannot be opened.".
If there exists such an ordering of plates, your program should print the sentence "Ordering is possible.". Otherwise, output the sentence "The door cannot be opened.".
Sample Input
3 2 acm ibm 3 acm malform mouse 2 ok ok
Sample Output
The door cannot be opened. Ordering is possible. The door cannot be opened.
题意:考古学家要打开一扇门,门上有许多磁质盘子,每个盘子上有仅由小写字母组成的一个单词,我们要将这些盘子按一定顺序排序,规定是一个单词的首字母必须是它的前一个单词的末字母,如果能行就输出 Ordering is possible.否则输出 The door cannot be opened.
给出T组测试数据,每组测试数据第一行有数字N,表示有N个盘子,接下来N行每行有一个单词。
思路:这道题,有一个很巧妙的转换,把点变成边。以26个字母作为顶点;对于每一个盘子,如果它的首字母为c1,末字母为c2,那么从c1向c2连一条有向边。然后判断图连通,再判断它是否为欧拉图。因为有重边,用边表建图时(在建图时加判断 用边表也可以)会超时,用邻接矩形比较好 因为只有26个点。
这种题实际上就是判断有向图的欧拉路的存在性。也就是对所给的所有单词,所有出现过的不同的字母就是图上的顶点,读入每一个单词,单词的首字母对应的点出度加1,末 字母对应的点入度加1,最后再来做判断。也就是所有字母对应的入度=出度 或是除了端点的字母各自的出入度相差1以外其余的顶点出度=入度,就满足条件->能构成链。 那么对于所有出现过的字母,只用判断只有一个的出度为入度加1而且只有一个的入度等于出度加1,或所有点的出度等于入度就可以了。当然首先图必须是连通的,这点很关键,这个可以用并查集来做。
通过图(无向图或有向图)中所有边一次且仅一次行遍图中所有顶点的通路称为欧拉通路,通过图中所有边一次且仅一次行遍所有顶点的回路称为欧拉回路。具有欧拉回路的图称为欧拉图(Euler Graph),具有欧拉通路而无欧拉回路的图称为半欧拉图。
欧拉回路要求边不能重复,结点可以重复. 笔不离开纸,不重复地走完所有的边,且走过所有结点,就是所谓的一笔画. 欧拉图或通路的判定: (1) 无向连通图G是欧拉图当且仅当G中不含奇数度顶点(G的所有结点度数为偶数)
(2) 无向连通图G是半欧拉图当且仅当G恰有两个奇数度的顶点; (3) 有向图D是欧拉图当且仅当D是强连通的并且每个结点的入度=出度 (4) 有向图D是半欧拉图当且仅当D是单向连通的且恰有两个奇度顶点,其中一个顶点入度比出度大1,另一个顶点出度比入度大1,其余每个顶点的入度=出度,
欧拉回路+并查集:
#include
#include
#include
#include
using namespace std;
int indeg[26],outdeg[26],father[26],visit[26];
//indeg入度,outdeg出度,father用于并查集操作(集合的代表元素),visit表征字母是不是已经用过了
int setfind(int x)
{
if(father[x]==-1)
return x;
return father[x]=setfind(father[x]);
}
void setUnion(int u,int v)
{
int fu=setfind(u);
int fv=setfind(v);
if(fu!=fv)
father[fv]=fu;
}
bool Judge()//判断是否为欧拉图
{
int sum1=0,sum2=0,sum3=0,i;
for(i=0;i<26;i++)
{
if(visit[i]==1&&father[i]==-1)//找祖先
sum1++;
if(fabs(indeg[i]-outdeg[i]-0.0)==1)
sum2++;
else if(indeg[i]!=outdeg[i])
sum3++;
}
if(sum3>0||sum2>2||sum1>1)
return false;
else
return true;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int N,i;
string word;
memset(indeg,0,sizeof(indeg)); //初始化操作
memset(outdeg,0,sizeof(outdeg));
memset(visit,0,sizeof(visit));
memset(father,-1,sizeof(father));
cin>>N;
for(i=0;i>word;
int len=word.size();
int u=word[0]-'a';//单词首字母
int v=word[len-1]-'a';//单词末字母
visit[u]=visit[v]=1;//单词已经用过了
setUnion(u,v);//连边v->u
outdeg[u]++;//单词首字母出度+1
indeg[v]++;//单词末字母入度+1
}
if(Judge())
cout<<"Ordering is possible."<
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
欧拉回路+DFS
#include
#include
#include
#include
using namespace std;
int indeg[26],outdeg[26],map[26][26],st;
//indeg入度,outdeg出度,map[i][j]=1表明i到j可连
bool Judge()
{
int sum1=0,sum2=0,sum3=0,i,temp;
for(i=0;i<26;i++)
{
if(indeg[i]-outdeg[i]==1)
sum1++;//终点
if(outdeg[i]-indeg[i]==1)
{ sum2++; st=i;}//祖先即起点,这种情况是形成欧拉通路而不是欧拉回路
if(indeg[i]==outdeg[i]&&indeg[i]!=0)
temp=i;
if(fabs(indeg[i]-outdeg[i]-0.0)>1)
sum3++;
}
if(sum3>0||sum2>1||sum1>1)
return false;
if(sum2==0)//表示形成欧拉回路
st=temp;//起点的赋值
return true;
}
void DFS(int u)
{
for(int i=0;i<26;i++)
if(map[u][i])
{
map[u][i]=0;
DFS(i);
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
int N,i,j;
string word;
memset(indeg,0,sizeof(indeg)); //初始化操作
memset(outdeg,0,sizeof(outdeg));
memset(map,0,sizeof(map));
cin>>N;
for(i=0;i>word;
int len=word.size();
int u=word[0]-'a';//单词首字母
int v=word[len-1]-'a';//单词末字母
map[u][v]=1;//连边
outdeg[u]++;//单词首字母出度+1
indeg[v]++;//单词末字母入度+1
}
bool flag=false;
if(Judge())
{
flag=true;
DFS(st);
for(i=0;i<26;i++)
for(j=0;j<26;j++)
if(map[i][j])//表示路径没有经过所有边,自然也就不是欧拉路
{
flag=false;
break;
}
}
if(flag)
cout<<"Ordering is possible."<