zoukankan      html  css  js  c++  java
  • Euleriar Path 入门

    一、前置技能

     >  图的概念

     >  dfs遍历图

     >  stack

     >  一笔画

    二、定义

    看过上面链接 是不是对一笔画产生了兴趣呢?

    (A:没有!)

    好吧……其实通俗来讲 欧拉路径就是OI意义下的一笔画

    也就是 图中经过每条边一次并且仅一次的路径

    欧拉回路就是满足欧拉路径性质的回路

    同时我们定义欧拉图(其实就是一笔画出来的图)

    存在欧拉回路的图称为欧拉图。
    存在欧拉路径但不存在欧拉回路的图称为半欧拉图。

    三、性质与定理

    这种路径很特殊 不一定所有的图都有(比如大部分树)

    规定一个点的度数为过这个点的边数(应该都知道)

    刨去孤立点(没有度数的点)之后(显然,这样做并不会影响图中欧拉回路的存在性。)

      >  Q:先考虑无向图

    发现我们考虑边无法推知下一步的方向 转而考虑点

    然后就可以发现 在欧拉路径中除了起点和终点 进入每个点一次的时候一定会出去一次

    所以除了起点和终点每个点的度数均为偶数

    而欧拉回路中起点和终点重合

    所以 欧拉图满足 每个点的度数为偶数

    半欧拉图满足 仅有两个点的度数为奇数

    那么 每个点度数为偶数的图(>0)一定有欧拉回路吗?

    证明:

    首先 如果图中没有回路 那么一定是一颗树 就一定有度数不是偶数的点(叶子)

    所以一定有回路

    然后比如我们找到了一个回路C

    当我们把这条回路上的边都不计的时候

    由于这是一条回路每一个点的度数减少量也一定是偶数(随手画个环看一下?)

    剩下的图中就一定还有回路 把两个回路拼起来就有新的回路

    最后全拼起来就能遍历所有的边 于是C就变成了欧拉回路

    (欧拉路证明类似)

     >  Q:那么有向图?

    同理 每条边有起点和终点 就把度数变成 入度出度 

    当入度==出度 也就是进入的边数和出去的边数一样的时候 满足是欧拉图

    仅有一个入度为1 仅有一个出度为1的时候 满足是半欧拉图

     > Q:那么混合图?

    (啪!)

    混合图欧拉回路是一个经典网络流问题 放别的地方讲

     >  Q:所以……怎么实现?

    其实刚刚证明的时候就已经说完了最常用的 套圈法 的基本过程

    实现的时候开一个栈存删掉的边(是否惰性删除都行)

    最后沿着栈逆序输出就OK了

    注意欧拉回路没有一定的起点 所以经常要输出字典序最小

    这个时候邻接矩阵就比较方便 当然像某些dalao把链前排序也行

    这里粘一下Code吧

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cmath>
     5 #define itn int
     6 #define ms(a,b) memset(a,b,sizeof a)
     7 #define rep(i,a,n) for(int i = a;i <= n;i++)
     8 #define per(i,n,a) for(int i = n;i >= a;i--)
     9 using namespace std;
    10 typedef long long ll;
    11 ll read() {
    12     ll as = 0,fu = 1;
    13     char c = getchar();
    14     while(c < '0' || c > '9') {
    15         if(c == '-') fu = -1;
    16         c = getchar();
    17     }
    18     while(c >= '0' && c <= '9') {
    19         as = as * 10 + c - '0';
    20         c = getchar();
    21     }
    22     return as * fu;
    23 }
    24 const int N = 550;
    25 //head
    26 int n,m;
    27 int a[N][N];
    28 int stk[N<<1],top;
    29 void dfs(int x) {
    30     rep(y,1,n) {
    31     if(!a[x][y]) continue;
    32     a[x][y]--,a[y][x]--;
    33     dfs(y);
    34     }
    35     stk[++top] = x;
    36 }
    37 int du[N];
    38 int main() {
    39     m = read();
    40     rep(i,1,m) {
    41     int x = read(),y = read();
    42     n = max(max(x,y),n);
    43     a[x][y]++,a[y][x]++;
    44     du[x]++,du[y]++;
    45     }
    46     bool flag = 1;
    47     rep(i,1,n) 
    48     if(du[i] & 1) {
    49         if(flag) dfs(i);
    50         flag = 0;
    51     }
    52     if(flag) dfs(1);
    53     while(top) printf("%d
    ",stk[top--]);
    54     return 0;
    55 }

    应该是luogu一道绿题吧……

    > 别忘了 总有人在等着你
  • 相关阅读:
    ubuntu16.04下vim安装失败
    Sql Server函数全解(三)数据类型转换函数和文本图像函数
    Sql Server函数全解(二)数学函数
    Sql server 2008 中varbinary查询
    处理乱码问题
    快速排序
    《Java编程思想》笔记 第二章 一切都是对象
    1021: 组合数末尾的零
    11462
    The Bus Driver Problem
  • 原文地址:https://www.cnblogs.com/yuyanjiaB/p/9764348.html
Copyright © 2011-2022 走看看