欧拉回路的一道不错的题目。(顺便总结下欧拉回路)
欧拉道路:能从无向图中的一个结点出发走出一条道路,每条边恰好经过一次。
如果一个无向图是连通的,且最多只有两个奇点(点的度数为奇数的点),则一定存在欧拉道路。
如果有两个奇点,则必须从其中一个奇点出发,另一个奇点终止;
如果奇点不存在,则可以从任意点出发,最终一定会回到该点。(称为欧拉回路)。
奇点不可能为奇数,一条边提供两个度,起点,终点,(假设有方向)则,度数必然两个两个增加,若奇点为奇数,则总的度数和必然为奇数。与度数两个两个增加矛盾。
如果为有向图:最多只能有两个点的入度不等于出度,而且其中一个必然是入度比出度大一(作为终点),另一个则为出度比入度大一(作为起点),若没有,则任意点为起点均可以,且最后必然会回到这点。
还有一个前提:不考虑边的方向的情况下,该图必须是连通的。
额,再说下题意。
给你很多个石板,然后按一定顺序排列,使这个字符串的最后一个字母和下一个字符串的首字母相同。
1e5的数据量,如果直接搜索会超时,(没试过,因为要把每个结点都试一遍,之后还要扫之后的每个),不知道会爆栈不……。
如果我们把每个字符串首字母当成起点,末字母当成终点,然后连线,想象出一个图(有向图),只需判断是否能构成一个欧拉道路即可。
先判断是否满足欧拉回路条件,然后用dfs判断该图是否连通。只需要判断有多少个结点在图上即可。
如果先判断是否连通的话,费时间比较长。
#include<cstdio>
#include<cstring>
const int MAXN=30;
const int inf=1000+10;
char temp[inf]; //输入的字符串
int G[MAXN][MAXN]; //判断有向图的边数,有一条+1;
int Gzero[MAXN],Gfinal[MAXN]; //起点的个数,终点的个数。即点的度数
bool letter[MAXN];
int nletter,cnt; //记录出现的字母个数,和最后判断多少个点在图上
bool start,end; //记录起点和终点是否只有一个
void dfs(int u){
if(cnt==nletter) return ;
if(!letter[u]) {letter[u]=true;cnt++;} //判断字母是否出现过
for(int i=0;i<26;i++) if(G[u][i]){G[u][i]=0;dfs(i);}
}
int main(){
//freopen("in.txt","r",stdin);
int T,n;
scanf("%d",&T);
while(T--){
int u=0,failed=0,x,y;
memset(G,0,sizeof(G));
memset(Gzero,0,sizeof(Gzero));
memset(Gfinal,0,sizeof(Gfinal));
memset(letter,0,sizeof(letter));
start=false; end=false; nletter=0,cnt=0;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%s",temp);
int lt=strlen(temp)-1;
x=temp[0]-'a'; //将首尾字母当成数字存起来,a到z表达成0到25;
y=temp[lt]-'a';
if(!letter[x]){nletter++;letter[x]=true;} //记录出现的字母的个数
if(!letter[y]){nletter++;letter[y]=true;}
Gzero[x]++; Gfinal[y]++; //每条边的起点和终点的度数
G[x][y]++; //记录有向边有多少条。不过好像记录过度数,标记下也行
}
for(int i=0;i<26;i++){
if(Gzero[i]==Gfinal[i]); //如果相等,则出度等于入度
else if(Gzero[i]==Gfinal[i]+1){ //如果出度比入度大一,只能为起点
if(!start){start=true;u=i;} //判断起点是否只出现过一次,并记录起点
else failed=1; //若出现不止一次,不存在欧拉回路
}
else if(Gzero[i]==Gfinal[i]-1){
if(!end) end=true; //与起点同理,不过不用记录终点
else failed=1;
}
else failed=1;
}
memset(letter,false,sizeof(letter)); //将字母全标记为假,dfs判断出现多少个字母
if(start && !failed) dfs(u); //如果存在欧拉回路且有唯一起点,递归判断
else if(!failed) dfs(x); //如果存在欧拉回路且没起点,随便dfs判断图是否连通
if(cnt!=nletter) failed=1; //如果有点不在图上,则不构成通路
if(failed) printf("The door cannot be opened.\n");
else printf("Ordering is possible.\n");
}
return 0;
}