题意:判断n个单词是否可以相连成一条链或一个环,两个单词可以相连的条件是 前一个单词的最后一个字母和后一个单词的第一个字母一样。取每个单词的收尾字母,想象成两个节点,这两个节点之间有个路径。这样就构成了一个图。
这题里,并查集只是一个辅助,用来判断图是不是连通的。真正用来判断的是欧拉回路。
定义:若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。若该路径是一个圈,则称为欧拉(Euler)回路。具有欧拉路径的图称为欧拉图(简称E图)。半欧拉图:没有欧拉环,但有至少一条欧拉路径的图。
判断:
以下判断基于此图的基图连通。
无向图存在欧拉回路的充要条件:一个无向图存在欧拉回路,当且仅当该图拥有奇数度数的顶点的个数为0且该图是连通图。
无向图是半欧拉图的充要条件:当且仅当该图是连通的且有且只有2个点的度数是奇数(此时这两个点只能作为欧拉路径的起点和终点)
有向图存在欧拉回路的充要条件:所有顶点的入度等于出度且该图是连通图,或者 一个顶点的度数(入度-出度)为1,另一个度数为-1,其他顶点的度数为0。有向图是半欧拉图的充要条件:当且仅当该图的基图(将所有有向边变为无向边后形成的无向图)是连通的且有且只有一个点的入度比出度少1(作为欧拉路径的起点),有且只有一个点的入度比出度多1(作为终点),其余点的入度等于出度。
混合图存在欧拉回路条件
要判断一个混合图G(V,E)(既有有向边又有无向边)是欧拉图,方法如下:假设有一张图有向图G',在不论方向的情况下它与G同构。并且G'包含了G的所有有向边。那么如果存在一个图G'使得G'存在欧拉回路,那么G就存在欧拉回路。其思路就将混合图转换成有向图判断。实现的时候,我们使用网络流的模型。现任意构造一个G'。用Ii表示第i个点的入度,Oi表示第i个点的出度。如果存在一个点k,|Ok-Ik|mod 2=1,那么G不存在欧拉回路。接下来则对于所有Ii>Oi的点从源点连到i一条容量为(Ii-Oi)/2的边,对于所有Ii<Oi的点从i连到汇点一条容量为(Oi-Ii)/2的边。如果对于节点U和V,无向边(U,V)∈E,那么U和V之间互相建立容量为无限大的边。如果此网络的最大流等于∑|Ii-Oi|/2,那么就存在欧拉回路。
#include <stdio.h>
#include <map>
#include <algorithm>
#include <string>
#include <string.h>
#include <iostream>
#define mm(a) memset(a, 0, sizeof(a))
using namespace std;
int father[26], vis[26];
int in[26], out[26];
int find_father(int x)
{
if(father[x] != x) father[x] = find_father(father[x]);
return father[x];
}
int main()
{
int T, n;
char s[1100];
scanf("%d", &T);
while(T--)
{
mm(in);
mm(out);
mm(vis);
for(int i = 0; i < 26; i ++)
father[i] = i;
scanf("%d", &n);
getchar();
for(int i = 0; i < n; i ++)
{
gets(s);
int len = strlen(s);
int u = s[0] - 'a', v = s[len - 1] - 'a';
vis[u] = vis[v] = 1;
out[u]++, in[v]++;
u = find_father(u), v = find_father(v);
if(u != v) father[u] = v;
}
int point = 0;
for(int i = 0; i < 26; i++)
{
if(vis[i] && father[i] == i)
point++;
}
if(point > 1)
{
puts("The door cannot be opened.");
continue;
}
int y = 0, z = 0, t = 0;
for(int i = 0; i < 26; i++)
{
if(vis[i] && in[i] != out[i])
{
if(in[i] == out[i] + 1) y++;
else if(in[i] + 1 == out[i]) z++;
else t++;
}
}
if(t)
puts("The door cannot be opened.");
else if((y == 1 && z == 1) || (z == 0 && y == 0))
puts("Ordering is possible.");
else
puts("The door cannot be opened.");
}
return 0;
}