首页 > 其他分享 >欧拉路径

欧拉路径

时间:2024-02-14 22:13:07浏览次数:32  
标签:连通 int 路径 second edge 欧拉

欧拉路径

欧拉路径

定义:可以一笔画走完且不重复经过一条边的路径

可用欧拉路径走完有向连通图判定:

  1. 所有点入度与出度之差 \(\le1\)
  2. 入度与出度之差为1的点个数为0或2(总度数为偶数,这种点不可能只有1个,若有2个则一起点一终点)

可用欧拉路径走完无向连通图判定:

度数为奇数的点的个数为0或2(不可能只1个,理由同上,若有2个则一起点一终点)


插播道题—— 【一本通提高篇欧拉回路】单词游戏

题意:若一个单词的第一个字母与另一个单词最后一个字母相同,则这两个词可接龙,每个词只能用一次,问是否能把给出的所有词接龙成功。

这道题不难,关键在于如何建图

接龙只用看首尾,中间没用

我们可以将每个词看作从首字母连向尾字母的一条有向边,看整个图是否有欧拉路径走完

判定如上,就不放代码了


那么问题来了,一个无向连通图中有几条极长欧拉路径呢?(互不共用边)

也就是这个图最少几笔能画完?

有下列情况:

  1. 有一条欧拉路径走完,判定见上
  2. 设此图有n个度数为奇数的点(\(n\) 为偶数且 \(n \not=\) \(0\) 或 \(2\)),则有 \(\frac{n}{2}\) 条欧拉路径

若图不连通就划分为几个连通图


如何找一条欧拉路径?

我们发现,从路径起点开始遍历图的每条边,回溯后将当前点加入path数组中,最后倒序输出即可

代码如下:

void dfs(int x)
{
    for(int i = minn; i <= maxn; i++)
        if(g[x][i])
        {
            g[x][i]--, g[i][x]--; // 邻接矩阵存图,把走过边删掉
            dfs(i);
        }
    path[++cnt] = x;
}                 
for(int i = minn; i <= maxn; i++)
   if(du[i] % 2)   
   {
      dfs(i); 
      flag = 1;
      break; // 无欧拉回路
   }
if(!flag)   dfs(minn);
for(int i = cnt; i > 1; i--)   printf("%d\n", path[i]);

P7771 【模板】欧拉路径

#include<bits/stdc++.h>
#define reg register
using namespace std;

const int N = 400010;
int n, m, u, v, ru[N], st, ed, chu[N], lin[N], cnt, head[N];
vector<int> edge[N];
inline void dfs(int x)
{
//	cerr << x << " "; 
	for(reg int i = head[x]; i < (int)edge[x].size(); i = head[x])
	{ // 注意,i = head[x],否则会跑满 m^2,时间复杂度不对
		head[x] = i + 1, dfs(edge[x][i]);
	}
	lin[++cnt] = x;
}
int main()
{
	scanf("%d%d", &n, &m);
	for(reg int i = 1; i <= m; ++i)
	{
		scanf("%d%d", &u, &v);
		edge[u].push_back(v), ++ru[v], ++chu[u]; 
	}
	for(reg int i = 1; i <= n; ++i)
		if(chu[i] != ru[i])
		{
			if(st && ed)	{printf("No");	return 0;}
			if(!st)	st = i;
			else if(!ed)	ed = i;	
		}
	if(st && !ed)	{printf("No");	return 0;}
	if(!st)	st = 1;
	for(reg int i = 1; i <= n; ++i)	sort(edge[i].begin(), edge[i].end());
	dfs(st);
	for(reg int i = cnt; i > 0; --i)	printf("%d ", lin[i]);
	return 0;
}

欧拉回路

定义:一条起点终点相同的欧拉路径

可用欧拉路径走完有向连通图判定:

  1. 所有点入度与出度之差<=1
  2. 入度与出度之差为1的点个数为0

可用欧拉路径走完无向连通图判定:

度数为奇数的点的个数为0

求路径同欧拉路径,若有字典序要求则把点/边排序

看道题—— 【一本通提高篇欧拉回路】欧拉回路

题目链接

思路则是求欧拉回路,不过输出可能会麻烦一些,要用边的号码判断反向或正向

代码如下——

#include<bits/stdc++.h>
using namespace std;
 
int t, n, m, v, u, du[100010], ru[100010], book[400010], path[100010], cnt;
vector<pair<int, int> > edge[100010];
int cmp(const pair<int, int> &a, const pair<int, int> &b)
{
   return a.second < b.second;
}
void dfs(int x)
{
   sort(edge[x].begin(), edge[x].end(), cmp); // 按字典序输出
   for(int i = 0; i < edge[x].size(); i++)
   {
       if(!book[edge[x][i].second])
       {
           book[edge[x][i].second] = 1;
           if(t == 1) 
           {
               if(edge[x][i].second <= m)   book[edge[x][i].second + m] = 1;
               else    book[edge[x][i].second - m] = 1;
           } //双向边两条都得去掉
           dfs(edge[x][i].first);
           if(t == 1)  path[++cnt] = edge[x][i].second > m ? (edge[x][i].second - m) * -1 : edge[x][i].second; // 判断方向
           else    path[++cnt] = edge[x][i].second; 
       }
   }
}
int main()
{
   scanf("%d%d%d", &t, &n, &m);
   for(int i = 1; i <= m; i++)
   {
       scanf("%d%d", &v, &u);
       edge[v].push_back(make_pair(u, i));
       if(t == 1)  edge[u].push_back(make_pair(v, i + m)), du[u]++, du[v]++;
       else    ru[u]++, du[v]++;
   }
   if(t == 1)
   {
       for(int i = 1; i <= n; i++)
           if(du[i] % 2)
           {
               printf("NO");
               return 0;
           }
   }
   else if(t == 2)
   {
       for(int i = 1; i <= n; i++)
           if(ru[i] != du[i])
           {
               printf("NO");
               return 0;
           }
   }
   // 判断有无欧拉回路
   for(int i = 1; i <= n; i++)
       if(du[i])
       {
           dfs(i);
           break;
       } // 找字典序最小点开始
   if(cnt != m)
   {
       printf("NO");
       return 0;
   }
   else
   {
       printf("YES\n");
       for(int i = cnt; i > 0; i--)
       {
           printf("%d ", path[i]); 
       } // 反向输出
   }
   return 0;
}

标签:连通,int,路径,second,edge,欧拉
From: https://www.cnblogs.com/KellyWLJ/p/18015669

相关文章

  • 代码随想录算法训练营第十七天| 110.平衡二叉树 257. 二叉树的所有路径 404.左叶
    110.平衡二叉树 题目链接:110.平衡二叉树-力扣(LeetCode)思路:判断平衡二叉树,就是判断两个子树的高度差,继而问题转化为了如何求子树的高度——后序遍历(主要卡在了这里)。递归函数返回的是树的高度,同时用-1来表示退出递归(一开始想着用bool型作为返回值,发现函数不好设计)。同时要关......
  • 路径覆盖与二分图匹配一一对应
    对任意一种路径覆盖,在二分图上选对应的边,肯定选出来的是一组匹配这就对应上去了难的主要是将二分图对应到一种路径覆盖上面去我们假设最开始把每个独立的点当做一条路径(即每个点既是起点也是终点),然后我们在二分图中每选一条边(注意是匹配边),就在DAG中选择对应的边,由于每次选择的是......
  • Linux下指定so动态库的加载路径的5种方法
    搜索的先后顺序是:编译目标代码时指定的动态库搜索路径;环境变量LD_LIBRARY_PATH指定的动态库搜索路径;配置文件/etc/ld.so.conf中指定的动态库搜索路径;默认的动态库搜索路径/lib;默认的动态库搜索路径/usr/lib。将库文件放置在对应的路径中,运行时就可以搜索到了。例1:通过gcc......
  • 冗余路径
    这道题目是一个模型:给连通的无向图加边,使得无向图没有桥(即变成边双连通分量),最小化加边数因为边双连通分量本来就没有桥,所以我们考虑对整个图求一遍边双连通分量(使用tarjan算法),然后将边双连通分量缩为一个点考虑。那么缩完点后得到的图一定是一棵树(因为图中不可能存在环)然后要......
  • 最短路径
    最短路算法主要有Floyd,Dijkstra,Bellman-Ford,SPFA,Jahnson,A*这六种算法。Floyd用来处理全源最短路,可以处理负边权。时间复杂度为\(\mathcal{O}(N^3)\)。Dijkstra用来处理单源最短路,不能处理负边权。时间复杂度最优为\(\mathcal{O}{(M\logM)}\)。Bellman-Ford用来处理单......
  • C#中获取进程当前路径各种方法的测试
    C#中获取进程当前路径各种方法的测试在CSharp中,获取当前进程的路径有很多种方式。同一个api在不同的运行和发布方式中,又会产生不同的效果。下面我用代码来测试一下效果,运行环境是:Windows10,.Net8。测试程序为放在``D:\的CurrentPathTest`目录。//不同的发布及运行方式//1.......
  • 断网测试3-彩票+路径数量
    第1题   彩票 查看测评数据信息每张彩票都印有6位数字,如果彩票的前三位数字的和恰好等于后三位数字的和,那么该彩票是"幸运彩票".输入格式 第一行,一个整数n,表示有n张彩票。1<=n<=1000。接下来有n行,每行是都印有6位数字。 输出格式 共n行,如果是"幸运彩票"输......
  • Python 获取相对路径
    想要获取当前文件的路径,通常我的做法是os.path.abspath(__file__)如果想要获取当前文件的所在文件夹,通常的做法是os.path.dirname(__file__)但是更多的时候,我想获取当前所在文件的父目录的父目录,做法可以是os.path.dirname(os.path.diranme(__file__))或path=os.path......
  • 次短路径问题
    一、问题描述P2865[USACO06NOV]RoadblocksG二、问题简析如果求最短路径,我们很自然会想到\(Dijkstra\)。但是,这道题要求的是次短路径。记到\(u\)的最短路径为\(d_1[u]\),到\(u\)的次短路径为\(d_2[u]\)。则\(d_2[v]=d_1[u]+e(u,v)\)or\(d_2[u]+e(u,v).w\)......
  • 修改SQLServer的TEMPDB路径
    数据库服务器上,SQLServer安装在C盘,导致C盘空间不足,每次都清理也释放不出来多少,经检查发现,安装目录下的tempdb.mdf有10多个G,随寻思把tempdb迁移到别的盘符。具体操作步骤如下:1、先在E盘建个目录tempdb;2、打开sqlserver管理界面,执行以下脚本ALTERDATABASEtempdbMODIFYFILE(N......