欧拉路径:在一个连通图里面每条边都只走一次且走完所有边的路径。
欧拉回路:在一个连通图里面从一个起点出发,每条边只走一次并且最后回到终点的一个回路。
欧拉回路是包含在欧拉路径里面的,只要欧拉路径的起点和终点是同一个点就是欧拉回路。
在一个欧拉路径里面,要有起点和终点,现在先看起点和终点是不同点的情形:
起点:起点最开始会有一条边1用于走出去,如果后面又通过一条边2走了回来,那么一定会通过一条边3走出去,由此可得,起点所连的边的数量一定是奇数。
终点:终点在最后会有一条没走过的边n可以进去,其余情况下进去和出去都要从别的两个条边进出,由此可得,终点连的边的数量也是奇数。
其他:其余非起点终点的点连的边都是偶数条。
欧拉回路:起点终点都是同一个点时就要保证所有点的数量都是偶数。
前提:所有边都是连通的
1.对于无向图
(1)存在欧拉路径的充分必要条件:度数为奇数的点只能有0个或者2个
(1)存在欧拉回路的充分必要条件:度数为奇数的点只能是0个
2.对于有向图
(1)存在欧拉路径的充分必要条件:所有点的入度等于出度;或者起点的的出度比入度多1,终点的入度比出度多1,其余点入度等于出度
(2)存在欧拉回路的充分必要条件:所有点的入度等于出度
1.铲雪车
信息学奥赛一本通(C++版)在线评测系统
思路:这图是有向图 然后每建一条边都是双向建的 所以每建一条边都会使得一个点的入度和出度+1 所以一定存在欧拉路径(欧拉回路)那么直接求距离就好了
#include
using namespace std;
int main()
{
double x1,y1,x2,y2;
cin>>x1>>y1;
double sum=0;
while(cin>>x1>>y1>>x2>>y2)
{
double dx=x1-x2;
double dy=y1-y2;
sum+=sqrt(dx*dx+dy*dy)*2;
}
int minutes=round(sum/1000/20*60);
int hours=minutes/60;
minutes%=60;
printf("%d:%02d\n",hours,minutes);
return 0;
}
2.欧拉回路
很普通的欧拉回路问题 但是要判断无解
无向图
1.所有点的度数都为偶数
2.所有边都是连通
有向图
1.所有点入度等于出度
2.所有点都是连通
代码细节:
1.由于边是从1开始编号 但是我们写代码的时候是从0开始的 所以 t 要+1
2.由于无向图其实就是特殊的有向图所以算无向图的时候可以直接把入度+出度看成无向图的度
3.由于 i 是引用的,所以修改 i 的值就相当于修改h[u] 所以每一次枚举都只会h[u]的第一条边
#include
using namespace std;
const int N=1e5+10,M=4e5+10;
int h[N],e[M],ne[M],idx;
int n,m,type;
int din[N],dout[N];
int cnt,ans[M];
bool used[M];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u)
{
for(int &i=h[u];~i;)//加了个引用来优化,让i一直等于h[u]
{
if(used[i])
{
i=ne[i];//删边
continue;
}
used[i]=true;//标记这条边用过了
if(type==1) used[i^1]=true;//标记反向边也用过了
int t;
if(type==1)
{
t=i/2+1;
if(i&1) t=-t;
}
else t=i+1;
int j=e[i];//先得到这条边
i=ne[i];//删除这条边
dfs(j);//遍历这条边
ans[++cnt]=t;//把这个路径存下来
}
}
int main()
{
scanf("%d",&type);
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
for(int i=0;i
3.骑马修栅栏
1124. 骑马修栅栏 - AcWing题库
显然是无向图的欧拉路径 但是要考虑输出字典序最小的路径
编号从小到大搜索就行了
#include
using namespace std;
const int N=510;
int n=500,m;
int g[N][N];
int ans[1100],cnt;
int d[N];
void dfs(int u)
{
for(int i=1;i<=n;i++)
if(g[u][i])
{
g[u][i]--,g[i][u]--;
dfs(i);
}
ans[++cnt]=u;
}
int main()
{
cin>>m;
while(m--)
{
int a,b;
cin>>a>>b;
g[a][b]++,g[b][a]++;
d[a]++,d[b]++;
}
int start=1;
while(!d[start]) start++;
for(int i=1;i<=n;i++)
if(d[i]%2)
{
start=i;
break;
}
dfs(start);
for(int i=cnt;i;i--)
printf("%d\n",ans[i]);
return 0;
}
4.单词游戏
把每个单词首尾看成一条有向边 一共有26个点 n条边 依次走过每一条边 那么就是判是否存在欧拉路径
这次不bfs 直接并查集
#include
using namespace std;
const int N=30;
int n,m;
int p[N];
bool st[N];
int din[N],dout[N];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
char str[1100];
int t;
cin>>t;
while(t--)
{
cin>>n;
memset(din,0,sizeof din);
memset(dout,0,sizeof dout);
memset(st,0,sizeof st);
for(int i=0;i<26;i++)
p[i]=i;
for(int i=0;i>str;
int len=strlen(str);
int a=str[0]-'a',b=str[len-1]-'a';
st[a]=st[b]=true;
dout[a]++,din[b]++;
p[find(a)]=find(b);
}
int start=0,ed=0;
bool success=true;
for(int i=0;i<26;i++)
{
if(din[i]!=dout[i])
{
if(din[i]==dout[i]+1)
ed++;
else if(din[i]+1==dout[i])
start++;
else
{
success=false;
break;
}
}
}
if(success&&!(!start&&!ed||start==1&&ed==1))
{
success=false;
}
int t=-1;
for(int i=0;i<26;i++)
if(st[i])
{
if(t==-1) t=find(i);
else if(t!=find(i))
{
success=false;
break;
}
}
if(success) puts("Ordering is possible.");
else puts("The door cannot be opened.");
}
return 0;
}