图论(欧拉路径)

这篇具有很好参考价值的文章主要介绍了图论(欧拉路径)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

理论:

所有边都经过一次,若欧拉路径,起点终点相同,欧拉回路
有向图欧拉路径:恰好一个out=in+1,一个in=out+1,其余in=out
有向图欧拉回路:所有in=out
无向图欧拉路径:两个点度数奇,其余偶
无向图欧拉回路:全偶

基础练习

P7771 【模板】欧拉路径
P2731 [USACO3.3] 骑马修栅栏 Riding the Fences
P1341 无序字母对

进阶

P3520 [POI2011] SMI-Garbage
题意:n点m条边以及边的目前状态目标状态,若干辆垃圾车跑欧拉回路,每次垃圾车经过改变路的状态
给出需要跑多少次欧拉回路和每次欧拉回路的路径才能所有边实现目标
思路:无向图欧拉回路拆环,
欧拉回路边只经过一次,于是当前状态与目标状态相同的边不用管
变成ol回路拆环问题,考虑在入栈的时候检查该元素是否在栈中,若在,表示成环。
由于常见的求欧拉路的程序给出的结尾都不是开头点,所以在dfs调用后栈里面还剩下一个环,输出即可。

#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<math.h>
#include<map>
#include<vector>
#include<stack>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
#define ms(x,y) memset(x,y,sizeof x);
#define YES cout<<"YES"<<'\n';
#define NO  cout<<"NO"<<'\n';
#define fr(i,z,n) for(int i = z;i <= n; i++)
#define ufr(i,n,z) for(int i = n;i >= z; i--)
#define fer(i,x)   for(int i=e.head[x];~i;i=e.next[i])
typedef long long ll;
const ll N= 1e6  + 10, inf = 1e18;
const ll mod = 1e9 + 7;
using namespace std;

int n, m;
int vist[N];            //标记点
int vis[N<<1];                     //标记边
int deg[N],instack[N];
int tot;
stack<int>sta;
vector<int>va[N];
template<size_t size>
struct Road {
	int to[size<<1], next[size<<1], head[size<<1], cnt = 1;
	ll w[size<<1];
	void add(int x, int y, ll ww) {
		to[cnt] = y;
		w[cnt] = ww;
		next[cnt] = head[x];
		head[x] = cnt++;
	}
	void clear(int n) {
		for (int i = 0; i <= n; i++) {
			head[i] = -1;
		}
		cnt = 0;
	}
	
};
Road <N> e; // 无向图 * 2
void dfs(int x) {
	vist[x] = 1;
	fer(i, x) {
		int v = e.to[i];
		if (!vis[i]) {        //边未标记,每条无向边只能走一次
			vis[i] = vis[i ^ 1] = 1;             //两条有向边组成无向边
			e.head[x] = e.next[i];       //下一次直接从nex[i]开始,降低时间复杂度
			dfs(v);
			if (instack[v]) {    
				va[tot].push_back(v);
				while (sta.top()!=v) {
					va[tot].push_back(sta.top());
					instack[sta.top()] = 0;
					sta.pop();
				}
				va[tot].push_back(v);
				tot++;
			}
			else {
				sta.push(v);
				//cout << v << '\n';
				instack[v] = 1;
			}
		}
	}
}
void solve() {
	scanf("%d %d", &n, &m);
	e.clear(n);
	fr(i, 1, m) {
		int x, y, f, t;
		scanf("%d %d %d %d", &x, &y, &f, &t);
		if (f ^ t) {      //相异,需要经过     
			e.add(x, y, 0);
			e.add(y, x, 0);
			deg[x]++;
			deg[y]++;
		}
	}
	int flag = 0;
	fr(i, 1, n) {
		if (deg[i] % 2) {           //无向图的欧拉回路应该为全偶
			flag = 1;
			break;
		}
	}
	if (flag) {
		printf("NIE\n");
		return;
	}
	fr(i, 1, n) {
		if (!vist[i]) {               //点未标记
			dfs(i);
			if (instack[i]) {    //多个环以i为起点,剩余最后一个环
				va[tot].push_back(i);
				while (!sta.empty()) {
					va[tot].push_back(sta.top());
					instack[sta.top()] = 0;
					sta.pop();
				}
				tot++;
			}
		}
	}
	printf("%d\n", tot);
	for (int i = 0; i < tot; i++) {
		printf("%d ", va[i].size()-1);
		for (auto it : va[i]) {
			printf("%d ", it);
		}
		printf("\n");
	}
}

signed main()
{
	ios;
	int t = 1;
	//cin >> t;
	while (t--) {
		solve();
	}
}

P3443 [POI2006] LIS-The Postman
题意:给定一个有向图,规定路线从1开始1结束,经过每条边恰好一次,同时给定一些序列
序列在路线中需要连续出现,求满足的路线
x,y<=n<=5e4,m<=2e5
思路:难点在于序列的合并
序列顺序要有边,同时序列的前驱和后继只能有一个,用E存边
 用pre,Next记录序列点的前驱后继在E的位置
重新建图(将序列合并),跑欧拉回路,stack入栈起点在在E的位置
最后还要确定每条边都用上文章来源地址https://www.toymoban.com/news/detail-744276.html

#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<math.h>
#include<map>
#include<vector>
#include<stack>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
#define ms(x,y) memset(x,y,sizeof x);
#define YES cout<<"YES"<<'\n';
#define NO  cout<<"NO"<<'\n';
#define fr(i,z,n) for(int i = z;i <= n; i++)
#define ufr(i,n,z) for(int i = n;i >= z; i--)
#define fer(i,x)   for(int i=e.head[x];i;i=e.next[i])
typedef long long ll;
const ll N = 1e6 + 10, inf = 1e18;
const ll mod = 1e9 + 7;
using namespace std;

int in[N];
template<size_t size>
struct Road {
    int to[size], next[size], head[size], cnt = 1;
    ll w[size];
    void add(int x, int y, ll ww) {
        to[cnt] = y;

        w[cnt] = ww;
        next[cnt] = head[x];
        head[x] = cnt++;
    }
    void clear(int n) {
        for (int i = 0; i <= n; i++) {
            head[i] = 0;
        }
        cnt = 1;
    }
};
Road<N>e;
int n, m;
map<int, int>H[N];
pair<int, int>E[N];
int pre[N], Next[N], b[N],vis[N];
stack<int>sta;
bool ans = 0;
void dfs(int x) {
    fer(i, x) {
        int v = e.to[i];
        if (!vis[i]) {
            vis[i] = 1;
            e.head[x] = e.next[i];
            dfs(v);
            sta.push(e.w[i]);           //入栈起点在E的位置
        }
    }
}
void solve() {
    cin >> n >> m;
    fr(i, 1, m) {
        int x, y;
        cin >> x >> y;
        E[i] = make_pair(x, y);     //记录边
        H[x][y] = i;    //记录边在E位置      
        in[y]++;
        in[x]--;
    }
    fr(i, 1, n) {
        if (in[i]) {        //有向图的欧拉路径in==out
            ans = 1;
        }
    }
    int k;
    cin >> k;
    fr(i, 1, k) {             
        int cnt,last;
        cin >> cnt;
        cin >> last;
        for (int j = 1; j < cnt; j++) {
            int y;
            cin >> y;
            if (H[last].find(y) == H[last].end()) {    //没有last->y的边
                ans = 1;
            }
            b[j] = H[last][y];
            last = y;
        }
        for (int j = 2; j < cnt;j++) {    //处理前驱后继以及边的合并
            if (!pre[b[j]]) {
                pre[b[j]] = b[j - 1];
            }
            else if (pre[b[j]] != b[j - 1]) {    //因为每条边只能出现一次
                ans = 1;
            }
            if (!Next[b[j-1]]) {
                Next[b[j - 1]] = b[j];
            }
            else if(Next[b[j-1]]!=b[j]) {
                ans = 1;
            }
        }
     }
    if (ans == 1) {
        cout << "NIE" << '\n';
        return;
    }
    int c = 0;
    fr(i, 1, m) {                  //建图
       if (!pre[i]) {
           ++c;
           int j;
           for (j = i; Next[j]; j = Next[j]) c++;
           e.add(E[i].first, E[j].second, i);        //i记录起点在E的位置
       }
    }
    if (c < m || !e.head[1]) {     //判断联通(c==m)和能否从1开始
        cout << "NIE" << '\n';
        return;
    }
    fr(i, 1, n) {             //建图后需要再判断
        if (in[i]) {
            cout << "NIE" << '\n';
            return;
        }
    }
    dfs(1);           //欧拉回路

    fr(i, 1, n) {                           
        if (e.head[i]) {                 //确定每条边都用上
            cout << "NIE" << '\n';
            return;
        }
    }

    cout << "TAK" << '\n';
    cout << 1 <<'\n';
    while (!sta.empty()) {
        int j = sta.top();
        sta.pop();
        while (j) {
            cout << E[j].second << '\n';
            j = Next[j];
        }
    }
}

signed main()
{
    ios;
    int t = 1;
    //cin >> t;
    while (t--) {
        solve();
    }
}

到了这里,关于图论(欧拉路径)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 图论——浅谈理论,DFS序和欧拉序

    提示:本文在树论基础上。 DFS 序:1 2 4 5 7 9 8 3 6. 欧拉序:1 2 4 4 5 7 9 9 7 8 8 5 2 3 6 6 3 1. 回加欧拉序 :1 2 4 2 5 7 9 7 5 8 5 2 1 2 3 6 3 1. 下文举例均指此图。 周所周知,DFS 为深度优先遍历,其框架如: 而 DFS 序就表示,DFS 遍历节点的顺序。 比如第 3 个遍历到的节点为 Q,则 DFS 序

    2024年01月19日
    浏览(31)
  • 离散数学 | 图论 | 欧拉图 | 哈密顿图 | 割点 | 桥(欧拉图和哈密顿图有没有割点和桥?)

    本文主要解决以下几个问题: 1.欧拉图能不能有割点,能不能有桥? 2.哈密顿图能不能有割点,能不能有桥? 首先我们要明白几个定义 割点 的定义就是在一个图G中,它本来是连通的,去掉一个点v以后这个图G就不连通了,那么点v就被叫做 割点 。 桥 的定义就是在一个图G中

    2024年02月08日
    浏览(28)
  • 欧拉路径和欧拉回路(Euler Path and Euler Circuit)解释

    欧拉路径(欧拉回路)是图论非常重要的组成部分,欧拉路径是数学家欧拉在研究著名的德国哥尼斯堡(Koenigsberg)七桥问题时发现的。这一发现直接导致了一门新的理论研究的诞生-图论问题。 欧拉路径和欧拉回路区别 在一个连通图上,如果从一个顶点出发,历经访问所有的边

    2024年02月11日
    浏览(27)
  • 【图论】关键路径求法c++

    代码结构如下图: 其中topologicalSort(float**, int, int*, bool*, int, int)用来递归求解拓扑排序,topologicalSort(float**, int*, int, int, int)传参图的邻接矩阵mat与结点个数n,与一个引用变量数组topo,返回一个布尔值表示该图是否存在拓扑排序,同时将引用变量数组topo赋值为该图的拓扑序列

    2024年02月03日
    浏览(31)
  • 【图论刷题-6】力扣 797. 所有可能的路径

    机器人的运动范围 矩阵中的路径 图像渲染 水位上升的泳池中游泳 寻找图中是否存在路径 所有可能的路径 力扣地址:https://leetcode.cn/problems/all-paths-from-source-to-target/ 这是一道比较典型的深度优先遍历、广度优先遍历案例,强烈推荐初学者完成这道题并且常常回来看看(也欢

    2024年02月06日
    浏览(31)
  • 【图论】图的概念和基本术语(顶点、边、度、路径等)

    在数学和计算机科学中,图是由 顶点(节点) 和 边(连接) 组成的一种 数据结构 ,用于描述对象之间的关系。图是一种广泛应用于许多领域的数学概念,包括计算机科学、网络分析、运筹学、社交网络分析等。 图可以用于表示各种现实世界中的问题,如社交网络中的用户

    2024年02月07日
    浏览(44)
  • 每天一道leetcode:797. 所有可能的路径(图论&中等&深度优先遍历)

    给你一个有 n 个节点的 有向无环图(DAG) ,请你找出所有从节点 0 到节点 n-1 的路径并输出( 不要求按特定顺序 ) graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j] 存在一条有向边)。 n == graph.length 2 = n = 15 0 = graph[i][j] n graph[i][j] != i (即不存

    2024年02月12日
    浏览(44)
  • 【图论C++】Floyd算法(多源最短路径长 及 完整路径)

    UpData Log👆 2023.9.29 更新进行中 Statement0🥇 一起进步 Statement1💯 有些描述可能不够标准,但能达其意 常见的有: DJ算法 、 Floyd算法 、 A*算法 、 Bellman-Ford 算法 、 SPFA算法 其中 A*算法 是 DJ算法 的plus版, SPFA算法 是 Bellman-Ford 算法 的plus版 算法名称 DJ算法 Floyd算法 SPFA算法

    2024年02月19日
    浏览(33)
  • 代码随想录图论 第一天 | 797.所有可能的路径 200. 岛屿数量

    代码随想录图论 第一天 | 797.所有可能的路径 200. 岛屿数量 一、797.所有可能的路径 题目链接:https://leetcode.cn/problems/all-paths-from-source-to-target/ 思路:求从0到n-1的所有路径,终止条件是当前节点为n-1。本题图的结构是group[][],group[x]表示x节点所能到达的所有节点的集合,深度

    2024年02月08日
    浏览(38)
  • 图论10-哈密尔顿回路和哈密尔顿路径+状态压缩+记忆化搜索

    求解哈密尔顿回路 如何求解一个图是否存在哈密尔顿回路呢? 一个最直观的想法就是暴力求解。暴力求解的思路也很简单:我们遍历图的每一个顶点 v,然后从顶点 v 出发,看是否能够找到一条哈密尔顿回路。 暴力求解的代价同求解全排列问题是等价的,其时间复杂度为

    2024年02月04日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包