目录html
有些东西不知道有什么用...但既然dls讲了就记记吧。不少东西来自国庆正睿 dls课件。
把之前的写的合并到一篇了。
也能够看这儿。算法
对于无向图,\(d_1,d_2,...,d_n\)为每一个点的度数。
有\(d_1+d_2+...+d_n=2e\)(每条边被计算两次)。
有偶数个度数为奇数的点。数组
给定一个由有限多个非负整数组成的度数序列,是否存在一个简单图使得其度数序列恰为这个序列。
令\(S=(d_1,d_2,...,d_n)\)为有限多个非负整数组成的非递增序列。
\(S\)可简单图化当且仅当有穷序列\(S’=(d_2-1,d_3-1,...,d_{d_1+1}-1,d_{d_1+2},...,d_n)\)只含有非负整数且是可简单图化的。
序列\(S\)可简单图化是指存在一个无向图(无重边无自环),使得其度数序列恰为\(S\)。
(这个其实就是很显然的东西。。主要是一个定义)优化
令\(S=(d_1,d_2,...,d_n)\)为有限多个非负整数组成的非递增序列。
\(S\)可简单图化当且仅当这些数字的和为偶数,且\[\sum_{i=1}^kd_i\leq k(k-1)+\sum_{i=k+1}^n\min(d_i,k)\]编码
对于任意\(1\leq k\leq n\)都成立。
也不难理解。对前\(k\)个点分配度数,除了两两能连\(\frac{k(k-1)}{2}\)条边外,剩下的度数由后面点的度数补。
由于\(d_i\)非递增,从小到大枚举\(k\),维护\(d_i\)后缀与\(k\)取\(\min\)的和(\(d_i,k\)都是单调的,维护从哪开始\(\min(d_i,k)\)的结果是\(d_i\))。就能够\(O(n)\)判断了。spa
例题:Good Bye 2018 E(居然真的遇到了),NEERC2013 K.Kids in a Friendly Class。.net
给定一张无向/有向图,求一条通过全部边刚好一次的回路。
有解当且仅当全部点 度数为偶数(无向)/入度等于出度(有向)。
任选一点开始dfs,每条边只通过一次。回溯时将回溯的边加入队列,最后队列的逆序就是答案。
时间复杂度 \(O(m)\).
欧拉路径也能够用同样的方法求出(找度数为奇数的点进行DFS)。3d
欧拉回路:有向图:全部点的出度入度都相等;从任意一点均可实现。
无向图:全部点度数都为偶数。
欧拉路:有向图:有两个点能够入度出度不相等(差不大于一),即起点终点;起点入度小于出度,终点入度大于出度 。
无向图:仅有两个点度数为奇数。
注:必须为连通图(用并查集判断)。
两笔画问题:
有解当且仅当入度为奇数的点不超过四个。
将其中两个点加一条边后求欧拉路径,而后在这条边处断开成两条欧拉路便可。
时间复杂度 \(O(m)\).code
UOJ.117(模板)、题集。htm
这个很全啊,能够看这儿。
Defination:
Prufer序列是一种无根树的编码表示。
对于一棵\(n\)个点的无根树,对应惟一一串长度为\(n-2\)的\(Prufer\)序列。
定义无根树中度数为\(1\)的节点是叶子节点,每次找到编号最小的叶节点删除,在序列中添加与之相邻的点。如此重复直到剩下最后两个节点。
上图对应无根树的\(Prufer\)序列为\(3,5,1,3\)。
给定点集\(G={1,2,\ldots,n}\),\(Prufer\)序列\([a_1,a_2,\ldots,a_{n-2}]\)。
每次取出\(Prufer\)序列中的第一个元素\(x_i\),在\(G\)中找在当前\(Prufer\)序列中没有出现的第一个元素\(y_i\),在\(x_i\)和\(y_i\)间连一条边;将\(x_i\)从\(Prufer\)序列中删除,\(y_i\)从\(G\)中删除。
最后\(G\)中还剩下\(2\)个元素,在这\(2\)个元素间连一条边。
Cayley定理:彻底图的生成树个数为\(n^{n-2}\)。
若是每一个点的度数为\(d_i\),那么生成树个数为\(\frac{(n-2)!}{(d_1-1)!(d_2-1)!...(d_n-1)!}\)。
每一个连通块大小为\(a_i\),那么添加一些边将这些连通块连通的生成树个数为\(a_1\times a_2\times...\times a_n\times(a_1+a_2+...+a_n)^{n-2}\)。
题集。
无向图生成树计数:令\(G=D-A\)(基尔霍夫矩阵=度数矩阵-边矩阵),而后去除\(G\)的任意一行一列获得\(G’\),\(G’\)的行列式即生成树个数。
有向图生成树计数:与无向图不一样的是,\(D\)矩阵为入度/出度矩阵分别对应外向树/内向树。且删掉第\(i\)行第\(i\)列表示以\(i\)为根节点的生成树个数。
题集。
一开始每一个连通份量是一个点自己。
每轮枚举全部属于不一样连通份量的边,每一个连通份量选择和其余连通份量相连的最小的边,而后合并。
每轮连通块个数至少减半,因此最多进行\(\log V\)轮。时间复杂度\(O(E\log V)\)。
具体实现直接用并查集便可。代码能够看这里。
通常用来作边权与点权相关,仍是个彻底图,求MST的题?
使得生成树树上最大边权值最小。
方法1:最小生成树必定是最小瓶颈生成树。
方法2:二分答案,看点是否连通。
方法3:
类比找第k大值的方法(nth_element
),首先随机一个边权\(w\)。而后将不超过这个边权的边加入,遍历这张图。
若是图连通,那么瓶颈不超过\(w\),因而只需考虑边权不超过\(w\)的边;不然将这些连通点缩起来,考虑边权大于\(w\)的边。
每次将问题的规模缩小至一半。指望时间复杂度\(T(m)=T(\frac m2)+O(m)=O(m)\)。
\(Dijkstra\)(贪心)或者\(Bellman Ford\)(动态规划)。
时间复杂度\(O(m\log n)\)或者\(O(nm)\)。
边权是\(0/1\):双端队列,若是是\(0\)在头部插入,不然在尾部插入。
最长路径不超过\(W\), 正权图:使用\(0...W\)的桶+链表维护这些点(代替堆),时间复杂度\(O(m+W)\)。
复杂度\(O(nm)\)。代码实现能够记录最短路树上的深度来判环,而不是入队次数,这样会有优化。
if(dis[v]>dis[u]+w) dis[v]=dis[u]+w dep[v]=dep[u]+1 if(dep[v]>n) return;
大致过程:http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html
考虑最短路中的松弛操做:if(dis[v]>dis[x]+w) dis[v]=dis[x]+w
,也就是强制使得\(dis[v]\)知足\(dis[v]\leq dis[x]+w\Rightarrow dis[v]-dis[x]\leq w\)。
因此对于\(x_j-x_i\leq w\)的限制,能够连一条边\((i\to j,w)\)。这样求\(x_n-x_0\)的最大值,就是求\(0\to n\)的最短路。
若是限制是\(x_j-x_i\geq w\),同理连边\((i\to j,w)\)。\(x_n-x_0\)的最小值就是求\(0\to n\)的最长路。
若是两种限制都有,就把\(\geq\)变成\(\leq\)。
解的存在性:
好比求\(x_n-x_0\)的最大值:若图中存在负环,则\(0\to n\)的最短路无穷小,则不存在最大值(无解)。
若\(0\)和\(n\)就不在同一连通块,则\(0\to n\)的最短路无穷大,最大值无穷大(或者存在无数多解)。
不然有解。
PS:
\(SPFA\)能够根据入队次数判负环,也能够据此判正环。虽然效率都不高就是了。
\(Dijkstra\)不能求最长路(本质是贪心)。
如何判断解惟一:
对原图求一遍最短路。将原图取反,边权取反,求一遍最长路。
一个标号对应的是能取到的最小值,一个是最大值。
若是相同则解惟一。(没什么用)
题集。
\(Floyd\):\(O(n^3)\)
\(Johnson\)算法(可用于负权图):\(O(nm\log n)\)
原理:首先给图中每一个点一个权值\(h(u)\), 把每条边的边权\(w(u,v)\)改为\(w(u,v)+h(u)-h(v)\)。
对于\(s\to t\)的一条路径\(p\),权值为
=
因此这么作不会改变最短路。(也能够看这儿)
实现:第一次SPFA预处理\(1\)到每一个点的距离\(dis\),记\(h(v)=dis(v)\)。而后把边权\(w(u,v)\)改成\(w(u,v)+h(u)-h(v)\)。
其中\(h(u)\)为给每一个点设定的权值,\(h(u)=dis[u]\)。
由不等式能够获得\(dis(u)+w(u,v)\geq dis(v)\),也就是改完以后全部边权非负。
以后能够每一个点用\(Dijkstra\)跑。就是\(O(nm\log n)\)啦。
这样也能够实现\(Dijkstra\)跑费用流。
(后面就直接抄dls课件了QAQ)
\(u\)的偏爱距 \(ecc(u)=\max\{dis(u,v)\}\)
直径 \(d=\max\{ecc(u)\}\)
半径 \(r=\min\{ecc(u)\}\ (d\neq2r)\)
中心 \(arg\ \min\{ecc(u)\}\)(要求定义在点上)
绝对中心(能够定义在边上)
相关:求最小直径生成树(差很少)。
实现:固定一条\((u,v)\),考虑上面的点\(p\)的偏爱距。
假设第三个点是\(w\), \(dis(p,u)=x\)。
那么对应的折线为\(\min\{x+dis(u,w),\ w(u,v)-x+dis(v,w)\}\)。
那么偏爱距为\(n\)条折线的最大值造成的折线。
按左端点排序维护一下。时间复杂度\(O(nm\log n)\)
即绝对中心的最短路树。
如何证实?
注意一棵树\(T\)的直径为半径的两倍(对绝对中心来讲)。若是最小直径生成树\(T’\)不包含绝对中心,那么取\(T’\)的绝对中心\(v\),显然矛盾。
每次去掉图中入度为\(0\)的点。
时间复杂度\(O(n+m)\)。
若是最后不为空集,那么这个图不为DAG。(不然每一个点入度不为0,即每一个点能够选择一个前趋,沿着前趋走根据抽屉原理必定能找到相同点,也就是一个环。)
按照反图DFS,出栈序列就是一个合法的拓扑序列。
scc缩点顺序也是一个合法拓扑序。
每一个点有不一样的标号,要使得拓扑序最小。
将拓扑排序的队列改为优先队列便可。
使得最后的拓扑序中1的位置尽可能靠前,若是相同比较2的位置,依次类推。
首先考虑如何求1最先出现的位置,能够将原图反向,而后每次弹除了1以外的元素,直到队列只剩下1为止。
这是反图中1的最晚的出现的位置,也就是原图中最先的。
根据是否在队列里,这个图被分红两部分,在对应的图中用一样的方法处理2,依次类推。
容易发现每次找尽可能大的元素出队,能完成上述的过程。
因此等价于反图最大字典序。
题集。
对于一个二分图\(G=(X,Y,E)\),记\(S\)为\(X\)的一个子集,\(N(S)\)为全部\(S\)中全部点的相邻点的并集。
一个图有完备匹配当且仅当\(X\)的全部子集\(S\)都有\(|S|\leq|N(S)|\)。
对通常图的推广:
推论: 每一个正则二分图都有完备匹配。
最小点覆盖=最大匹配 (与最大流最小割定理等价)
最大独立集=点数-最大匹配 (独立集为点覆盖的补集)
最小边覆盖=最大独立集 (独立集中每一个点须要一条边去覆盖)
覆盖全部的边:每条边下界设为1, 而后求最小流。
覆盖全部的点:创建二分图,对于\(u\to v\)的边,看作二分图中的\((u,v’)\),而后答案为点数-最大匹配。
\(Dilworth\)定理: 最大反链=最小链覆盖;最短的最长链=最小反链划分数-1(?存疑。见BZOJ4160)。(固然这个不该该只放在二分图部分的)
题集。
\(Tarjan\)。
将一个图的全部强联通份量缩起来会获得一个DAG。
点连通度: 最小的点集使得删去以后图不连通
边连通度: 最小的边集使得删去以后图不连通
若是一个图的点连通度大于1,那么是点双连通的,边连通同理。
双联通份量为图中的极大双联通子图。
考虑DFS树,每条非树边对应着一个点到祖先的路径。对于一条非树边只要把对应的边打上标记便可。
好比对于\((u,v)\)这条非树边,只要在\(u\)点打上\(+1\)的标记,\(v\)点打上\(-1\)的标记。
\(x\)到\(fa[x]\)的树边的覆盖次数为子树内全部标记的和。
割点同理(注意特判根节点和叶节点)。
(没看懂下面要干吗)
题集。
一堆变量的二元限制。
问是否存在合法的赋值。
将原坐标系每一个点的坐标\((x,y)\)变为\((x+y,x-y)\),则原坐标系中的曼哈顿距离等于新坐标系中的切比雪夫距离。
反过来,将原坐标系每一个点的坐标\((x,y)\)变为\((\frac{x+y}{2},\frac{x-y}{2})\),则原坐标系中的切比雪夫距离等于新坐标系中的曼哈顿距离。
例题:BZOJ3170 松鼠聚会。