【知识点小结】关于图论的性质和技巧

哈密路回路

如果一个总点数至少为3的简单图G满足:G的任意两个点u和v度数之和至少为n,即deg(u)+deg(v)≥n,那么G必然有哈密顿回路。
可以n^2构造

看这篇博客

欧拉回路

中国邮差问题

邮差叔叔走访每条大街小巷,让家家户户都收到信。

给定一张图,找出一条环状路线(起点和终点相同),图上每条边至少经过一次,并且距离最短。
如果求路径,则匹配的时候少匹配一对点

无向图演算法

http://web.mit.edu/urban_or_book/www/book/chapter6/6.4.4.html

  1. 先判断整张图是否连通,否则无解。
  2. 找出图上所有奇点,一定是偶数个。
  3. 找出所有奇点点对之间的最短路径长度。
  4. 把这些奇点做最小权匹配,权重采用刚才算的最短路径长度。
  5. 把匹配边加在原图上,再找欧拉环,即得中国邮差路径之权重。
  6. 将匹配边改成其代表的最短路径,即得中国邮差路径。
    时间复杂度为六项步骤总和。各条匹配边所代表的最短路径,绝对不会重叠。
有向图演算法
  1. 先判断整张图是否为一个强连通分量,否则无解。
  2. 找出图上所有出边数不等于入边数的点。
  3. 于上述找到的点,找出所有点对之间的最短路径长度。
  4. 令d(x)为x点出边与入边的数量差。
    出边多于入边的点x,建立d(x)份,放在X侧。
    出边少于入边的点y,建立d(y)份,放在Y侧。
    最后建立X侧到Y侧的边,权重采用刚才算的最短路径长度。
    算最小权二分匹配。
  5. 合理的做法是建立最小权最大流模型:
    把出边多于入边的点x,放在X侧。拉一条源点到x点的边,权重为零,容量为d(x)。
    把出边少于入边的点y,放在Y侧。拉一条y点到汇点的边,权重为零,容量为d(y)。
    最后建立X侧到Y侧的边,权重采用刚才算的最短路径长度,容量为无限大。
    算最小权最大流。
  6. 把匹配边加在原图上,再找欧拉环,即得中国邮差路径之权重。
  7. 将匹配边改成其代表的最短路径,即得中国邮差路径。<
欧拉回路新的求法:Hierholzer’s algorithm

大概是先找从v出发回到v的一个回路,然后再基于当前回路增广。每次加入一个圈。保证每次求完都是一个圈。
要用双向链表实现,比较麻烦。
有个好处就是不会像直接dfs那样留出不完整的环,在动态开点的欧拉回路问题中有点用

一些例题

bzoj 2935: [Poi1999]原始生物

对每一个联通块,入度大的向出度大的点连边,直到出入度相等。最后在欧拉回路上删除一条边即得欧拉路径
不求方案不需要真正连边

总结
欧拉回路经常与边的定向,要求遍历所有序列等问题有关
常用的思路是将哈密顿回路问题转化为欧拉回路,从而变得可解

图的计数技巧

对度数根号n分治
统计三元环、四元环个数:O(m* sqrt(m))

udpate
直接把边按照度数从小到大定向。那么每个点的出边显然只有sqrt(m)条
三元环:
直接标记所有出边,才枚举出边的出边统计标记
四元环:
在度数最大处统计
枚举其对面的点,走两步,每走到一次该点统计答案并把标记+1
四条边的联通块:自己分类讨论算重的情况,但要注意技巧,不能把讨论情况分得太多
正戊烷 + 新戊烷 + 异戊烷 - (三元环 + 边和三元环)* 3 - 四元环 * 3

这是ICPC 2018 焦作的L题

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

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;

const int maxn = 2e5 + 10;
const int mod = 1e9 + 7;
const int inv2 = (mod + 1) >> 1;

int n,m,deg[maxn],pos[maxn],order[maxn],vis[maxn];
vector <int> adj[maxn],graph[maxn];

//====================================basic operation===============================
inline void add(int &x, int y) {
   
  x += y;
  if (x >= mod) {
   
    x -= mod;
  }
}

inline void sub(int &x, int y) {
   
  x -= y;
  if (x < 0) {
   
    x += mod;
  }
}

inline int mul(int x, int y) {
   
  return (int) ((long long) x * y % mod);
}
inline int power(int x, int y) {
   
  int res = 1;
  while (y) {
   
    if (y & 1) {
   
      res = mul(res, x);
    }
    x = mul(x, x);
    y >>= 1;
  }
  return res;
}
//====================================================================&#
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值