题目
一、无向图
每个顶点的度数都是偶数,则存在欧拉回路。
二、有向图(所有边都是单向的)
每个节顶点的入度都等于出度,则存在欧拉回路。
三.混合图欧拉回路
混合图欧拉回路用的是网络流。
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
什么时候可以不重复的走完所有边?
(1)对于无向图来说,就是所有点的度为偶数(欧拉回路),或者有且只有两个点的度为奇数其他点为均为偶数(且一定是从一个奇点开始,到另一个奇点结束)(欧拉通路)
(2)对于有向图来说就是所有点的入度与出度都相等(欧拉回路)或者存在一个点入度比出度大一(终点),存在另一个点出度比入度大一(起点),其他点的入度与出度相等。(从起点开始,到终点结束)(欧拉通路)
思路:
将每个单词的首、尾字母看成点,单词看成边,构成一个有向图
代码如下:
dfs
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn=100;
int n;
int G[maxn][maxn],vis[maxn],in[maxn],out[maxn];
void dfs(int u)
{
vis[u]=1; //访问标记
for(int v=0;v<26;v++) //字母节点
if(!vis[v]&&G[u][v])
dfs(v); //没有被访问并且有有向边
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
char s[100005];
memset(vis,1,sizeof(vis)); //标志是否被遍历过
memset(G,0,sizeof(G));
memset(in,0,sizeof(in)); //入度
memset(out,0,sizeof(out)); //出度
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",s);
int len=strlen(s);
int r=s[0]-'a'; //首
int t=s[len-1]-'a'; //尾
G[r][t]=1; //有有向边
in[t]++;
out[r]++; //很重要!!!,出入度别写反了,
vis[r]=vis[t]=0; //将其置为未访问状态
}
int flag=0,cnt1=0,cnt2=0,cnt3=0,p=0;
for(int i=0;i<26;i++)
{
if(in[i]==out[i]) //环的情况
continue;
else if(out[i]==in[i]+1) //起点
{
p=i;
cnt1++;
}
else if(in[i]==out[i]+1) //终点
cnt2++;
else cnt3++; //没有满足
}
if(cnt3>0)
{
printf("The door cannot be opened.\n");
continue;
}
if(cnt1==0&&cnt2==0 || cnt1==1&&cnt2==1) //组成环或者一条直线
flag=1;
else flag=0;
dfs(p);
for(int i=0;i<26;i++)
if(!vis[i]) flag=0;
if(flag==1) printf("Ordering is possible.\n");
else printf("The door cannot be opened.\n");
}
return 0;
}
并查集
#include<bits/stdc++.h>
using namespace std;
const int maxn=100;
const int inf=0x3f3f3f3f;
typedef long long ll;
int book[maxn],f[maxn],in[maxn],out[maxn];
int getf(int x)
{
if(x==f[x])
return x;
return f[x]=getf(f[x]);
}
void mer(int u,int v)
{
int t1=getf(u);
int t2=getf(v);
if(t1!=t2)
f[t2]=t1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
string s;
int n;
cin>>n;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(book,0,sizeof(book));
for(int i=0;i<26;i++)
f[i]=i;
for(int i=0;i<n;i++)
{
cin>>s;
mer(s[0]-'a',s[s.size()-1]-'a');
out[s[0]-'a']++;
in[s[s.size()-1]-'a']++;
book[s[0]-'a']=book[s[s.size()-1]-'a']=1;
}
int a=0,b=0,ans=0,flag=1,mark=1;
for(int i=0;i<26;i++)
{
if(book[i])
{
if(f[i]==i)
ans++;//只能有一个祖宗,即起点
if(in[i]!=out[i])
{
if(in[i]==out[i]+1)
a++;
else if(out[i]==in[i]+1)
b++;
else
mark=0;
}
if(ans>1||!mark)
{
flag=0;
break;
}
}
}
if(flag&&mark)
{
if((!a&&!b)||(a==1&&b==1))
cout<<"Ordering is possible."<<endl;
else
cout<<"The door cannot be opened."<<endl;
}
else
cout<<"The door cannot be opened."<<endl;
}
}