做题还是得站在原有结论的基础上,否则很浪费时间的。就像这次,开始的时候想自己想办法判通路,但是没有成功,后来看了欧拉判断法则,才把程序写出来。
代码如下:
#include <stdio.h>
#include <string.h>
int str[27][27], visit[27], du[27][2];//用数组记录字母的出度与入度
void read()
{//读取字符串,记录开头与结尾的字母
int n;
char por, tear, temp;
scanf("%d",&n);
getchar();
while(n--)
{
scanf("%c",&por);
du[por-'a'][1]++;
while((temp=getchar())!='\n')
tear = temp;
du[tear-'a'][0]++;
str[por-'a'][tear-'a'] = 1;
}
}
void dfs(int s)
{//深搜,找是否有通路
visit[s] = 1;
for(int i = 0; i < 26; i++)
{
if(str[s][i]&&!visit[i])
dfs(i);
}
}
int solve()
{
int head = -1, tear = -1;
for(int i = 0,count = 0; i < 26; i++)
{//检查出度与入度,是否满足出度与入度相等,否则最多相差1.
if(du[i][0] != du[i][1])
{
if(du[i][0]-du[i][1]>=2&&du[i][0]-du[i][1]<=-2)return 0;
else
{
count++;
if(du[i][1]-du[i][0]==1) head = i;
else tear = i;
}
}
if(count>2)return 0;//如果出现多个入度与出度相差1的节点,则肯定不能有且只有一条通路
}
if(head==-1&&tear==-1)//如果是欧拉回路的话
{
for(int i = 0; i < 26; i++)
if(du[i][0]){dfs(i); break;}
}
else if(head==-1||tear==-1)return 0;//如果不满足条件“开头节点出度比入度大1和结尾的节点出度比入度小1”
else dfs(head);//否则就从头开始搜索
for(int i = 0; i < 26; i++)
if(((du[i][0]+du[i][1])&&visit[i])||(!(du[i][0]+du[i][1])&&!visit[i]));//看其是否为通路(即有度的节点必须访问到)
else return 0;
return 1;
}
int main ()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(str, 0, sizeof(str));
memset(visit,0,sizeof(visit));
memset(du, 0, sizeof(du));
read();
if(solve())puts("Ordering is possible.");
else puts("The door cannot be opened.");
}
return 0;
}