平时做有向图欧拉回路的题时,我们都默认图是弱连通的,但是今天这道题需要判断。
就是一道有向图欧拉回路的判定,关键在于判断图是否连通,这里我们用并查集来判断图是否连通。
/*
有向图判定欧拉回路,难点在于判断图是不是连通,利用并查集
*/
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
const int MAX_N = 1e5+5;
struct edge
{
int v,next;
}e[MAX_N];
int p[MAX_N],eid;
void init()
{
memset(p,-1,sizeof(p));
eid = 0;
}
void insert(int u,int v)
{
e[eid].v = v;
e[eid].next = p[u];
p[u] = eid++;
}
int n,degree[MAX_N];
void euler()
{
int first = 0,last = 0;
for(int i=1;i<=26;i++)
{
if(degree[i]<-1 || degree[i]>1)
{
cout<<"impossible"<<endl;
return ;
}
else if(degree[i] == -1)
{
if(first != 0)
{
cout<<"impossible"<<endl;
return ;
}
else
first = i;
}
else if(degree[i] == 1)
{
if(last != 0)
{
cout<<"impossible"<<endl;
return ;
}
else
{
last = i;
}
}
}
if(first == 0 && last == 0)
{
cout<<"Euler loop"<<endl;
}
else if(first != 0 && last != 0)
{
cout<<"Euler path"<<endl;
}
}
//并查集部分,用来判断图是不是连通
int father[30];
int find(int x)
{
int r = x;
while(father[r] != r)
r = father[r];
int j, i=x;
while(i!=r) //路径压缩
{
j = father[i]; //在改变上级之前用临时变量j记录下它的值
father[i] = r; //把上级改为根节点
i=j;
}
return r;
}
void join(int x,int y) //判断x,y是否连通
/*如果已经连通,就不用管了 如果不连通,
就把它们所在的连通分支合并起,*/
{
int fx = find(x),fy=find(y);
if(fx!=fy)
father[fx]=fy;
}
bool vis[30];
int jilu[30],cnt = 0;
int main()
{
for(int i=1;i<=26;i++)
father[i] = i; //初始化26个字母分别对应1-26个数,他们自己的父节点一上来都是自己
cin>>n;
for(int i=0;i<n;i++)
{
int u,v;
string s;
cin>>s;
u = s[0] - 'a' + 1;
v = s[s.length()-1] - 'a' + 1;
insert(u,v);
degree[u]--;
degree[v]++;
if(!vis[u])
{
vis[u] = true;
jilu[cnt++] = u;
}
if(!vis[v])
{
vis[v] = true;
jilu[cnt++] = v;
}
join(u,v);
}
for(int i=0;i<cnt-1;i++)
{
if(find(jilu[i]) != find(jilu[i+1]))
{
cout<<"impossible"<<endl;
return 0;
}
}
euler();
return 0;
}