zoukankan      html  css  js  c++  java
  • 欧拉回路学习笔记

    1.定义

    通俗的讲,欧拉回路是从图上某一点出发,经过一系列不重复的边,然后再回到开始节点的路径。
    注意,这个过程可以经过重复的节点 比如图中仅有一个点,有 (998244353) 个自环,但这些自环仍然可以构成欧拉回路。

    2.存在条件

    • 有向图
      每个节点入度等于出度
    • 无向图
      每个节点度均为偶数

    3.求解方法

    比较简单,从一个点出发进行dfs,在回溯的时候把当前边加入答案队列。
    但有以下情况需要考虑

    • 图不连通
      无解。前提是至少两个连通块内有边
    • 单独一个点
      可以忽略,不对答案产生影响。因为欧拉回路关心的是经过所有边 单独一个点不会影响答案
    • 优化
      如果不加当前弧优化,复杂度是 (O(nm))
      加上后能优化到 (O(n+m))

    4.例题&代码

    模板-UOJ117
    分别对有向图和无向图找出欧拉回路,输出路径。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #include<cstring>
    #include<stack>
    #include<queue>
    #include<vector>
    #include<bitset>
    #define ll long long
    using namespace std;
    const int inf = 0x7fffffff;
    int T,n,m;
    #define maxn 400009
    int in[maxn],ans[maxn],out[maxn];
    int nxt[maxn],head[maxn],to[maxn];
    bool ban[maxn],vis[maxn];
    namespace fuckccf//无向边 
    {
    	int num=0,cnt=1;//!!!从1开始记录 
    	void Add(int x,int y){cnt++;nxt[cnt]=head[x];to[cnt]=y;head[x]=cnt;}//邻接表 
    	void dfs(int x)
    	{
    		ban[x]=1;
    		for(int &i=head[x];i;i=nxt[i])//当前弧 
    		{
    			int t=to[i],j=i>>1,val=i;//!!!进行完dfs之后i的值会改变 要提前存下来 
    			if(vis[j])continue;
    			vis[j]=1;
    			dfs(t);
    			num++;
    			if(val&1)ans[num]=-j;//如果是正向的 i末尾是0 否则是1 
    			else ans[num]=j;
    		}
    	}
    	void main()
    	{
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=m;i++)
    		{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			Add(x,y);
    			Add(y,x);
    			in[x]++;
    			in[y]++;
    		}
    		for(int i=1;i<=n;i++)if(in[i]&1){printf("NO
    ");return;}//判断无解 
    		for(int i=1;i<=n;i++)
    		{
    			if(!ban[i])dfs(i);
    			if(num&&num<m)//走了一些边,但没走完,说明图不连通或者无解 
    			{
    				printf("NO
    ");
    				return;
    			}
    		}
    		printf("YES
    ");
    		
    		for(int i=m;i>=1;i--)
    		{
    			printf("%d ",ans[i]);
    		}
    	}
    }
    namespace tymXINzhy//有向边 
    {
    	int num=0,cnt=0;
    	void Add(int x,int y){cnt++;nxt[cnt]=head[x];to[cnt]=y;head[x]=cnt;}
    	void dfs(int x)
    	{
    		ban[x]=1;
    		for(int &i=head[x];i;i=nxt[i])
    		{
    			int t=to[i],val=i;
    			if(vis[i])continue;
    			vis[i]=1;
    			dfs(t);
    			num++;
    			ans[num]=val;//直接记录边即可 
    		}
    	}
    	void main()
    	{
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=m;i++)
    		{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			Add(x,y);
    			in[y]++;
    			out[x]++;
    		}
    		
    		for(int i=1;i<=n;i++)if(in[i]!=out[i]){printf("NO
    ");return;}
    		for(int i=1;i<=n;i++)
    		{
    			if(!ban[i])dfs(i);
    			if(num&&num<m)
    			{
    				printf("NO
    ");
    				return;
    			}
    		}
    		printf("YES
    ");
    		for(int i=m;i>=1;i--)
    		{
    			printf("%d ",ans[i]);
    		}
    	}
    }
    signed main()
    {
    //	freopen("h.in","r",stdin);
    	scanf("%d",&T);
    	if(T==1)fuckccf::main();
    	else tymXINzhy::main();
    	return 0;
    }
    `
  • 相关阅读:
    linux系统swap分区容量扩展
    linux系统lv_root分区容量扩展
    linux系统创建新LV,挂载新分区。
    linux 服务器重启后lvm 变成inactive状态解决
    Linux下使用fdisk扩大分区容量
    go语言 调用飞书群消息机器人接口
    SpringCloud Sentinel 学习笔记
    Git 笔记整理
    SpringBoot 整合 RabbitMQ 学习笔记
    js递归生成树形结构-vue
  • 原文地址:https://www.cnblogs.com/lzy-blog/p/15426261.html
Copyright © 2011-2022 走看看