Add license and bages, change urls

This commit is contained in:
mbinary 2019-01-31 12:09:46 +08:00
parent b6805c66ce
commit b69b5641d0
84 changed files with 1519 additions and 1339 deletions

12
LICENSE Normal file
View File

@ -0,0 +1,12 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Copyright (C) 2019 Heqin Zhu <zhuheqin1@gmail.com>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@ -1,5 +1,13 @@
# Algorithm
# Algorithm and data structures
[![Stars](https://img.shields.io/github/stars/mbinary/algorithm-in-python.svg?label=Stars&style=social)](https://github.com/mbinary/algorithm-in-python/stargazers)
[![Forks](https://img.shields.io/github/forks/mbinary/algorithm-in-python.svg?label=Fork&style=social)](https://github.com/mbinary/algorithm-in-python/network/members)
[![repo-size](https://img.shields.io/github/repo-size/mbinary/algorithm-in-python.svg)]()
[![License](https://img.shields.io/badge/LICENSE-WTFPL-blue.svg)](LICENSE)
[![Language](https://img.shields.io/badge/language-python3-orange.svg)]()
<!-- [![Build](https://travis-ci.org/mbinary/PL0-compiler.svg?branch=master)]() -->
>Notes and codes for learning algorithm and data structures :smiley:
Some pictures and ideas are from `<<Introduction to Algotithm>>`
@ -7,10 +15,11 @@ Some pictures and ideas are from `<<Introduction to Algotithm>>`
I use python 3.6+ and c/c++ to implement them.
# Notice
Currently, Github can't render latex math formulas.Thus,if you want to view the markodwn notes which contain latex math formulas, you can visit [my blog](https://mbinary.coding.me)
Currently, Github can't render latex math formulas.Thus,if you want to view the markodwn notes which contain latex math formulas, you can visit [my blog](https://mbinary.xyz)
# Index
* [.](.)
* [LICENSE](./LICENSE)
* [README.md](./README.md)
* [backtracking](./backtracking)
* [dataStructure](./dataStructure)
@ -74,6 +83,7 @@ Currently, Github can't render latex math formulas.Thus,if you want to view the
* [binary_search.hs](./search/binary_search.hs)
* [bloomFilter.py](./search/bloomFilter.py)
* [schedule.py](./search/schedule.py)
* [work_dispatch.py](./search/work_dispatch.py)
* [sort](./sort)
* [binaryTree.py](./sort/binaryTree.py)
* [heapSort.py](./sort/heapSort.py)
@ -88,6 +98,7 @@ Currently, Github can't render latex math formulas.Thus,if you want to view the
* [manacher.py](./string/manacher.py)
* [markov.py](./string/markov.py)
* [rabin_karp.py](./string/rabin_karp.py)
* [rotate.py](./string/rotate.py)
* [src](./string/src)
* [sunday.py](./string/sunday.py)
* [wildcard_matching.py](./string/wildcard_matching.py)

View File

@ -3,7 +3,7 @@
# File : allOoneDS.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:07
# Description:

View File

@ -3,7 +3,7 @@
# File : testAllOne.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:07
# Description:

View File

@ -3,7 +3,7 @@
# File : bTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-08-29 12:49
# Description:

View File

@ -3,7 +3,7 @@
# File : binaryHeap.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:06
# Description:

View File

@ -3,7 +3,7 @@
# File : binaryTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:07
# Description:

View File

@ -3,7 +3,7 @@
# File : adjacentList.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-04-26 10:33
# Description:

View File

@ -3,7 +3,7 @@
# File : directed.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-04-26 10:33
# Description:

View File

@ -3,7 +3,7 @@
# File : graph.cc
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-04-26 10:33
# Description:

View File

@ -3,7 +3,7 @@
# File : undirected.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-04-26 10:33
# Description:

View File

@ -3,7 +3,7 @@
# File : hashTable.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-08 16:39
# Description:

View File

@ -3,7 +3,7 @@
# File : huffman.cc
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-04-25 22:32
# Description:

View File

@ -3,7 +3,7 @@
# File : intervalTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-18 10:48
# Description:

View File

@ -3,7 +3,7 @@
# File : leftHeap.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:06
# Description:

View File

@ -3,7 +3,7 @@
# File : loserTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:06
# Description:

View File

@ -3,7 +3,7 @@
# File : map.cc
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-04-26 10:33
# Description:

View File

@ -3,7 +3,7 @@
# File : polynomial.cpp
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:07
# Description:

View File

@ -3,7 +3,7 @@
# File : polynomial.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:07
# Description:

View File

@ -3,7 +3,7 @@
# File : redBlackTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-14 16:15
# Description:

View File

@ -3,7 +3,7 @@
# File : redBlackTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-14 16:15
# Description:

View File

@ -3,7 +3,7 @@
# File : splayTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:06
# Description:

View File

@ -4,7 +4,7 @@
# File : mapSum.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-14 23:11
# Description:

View File

@ -4,7 +4,7 @@
# File : maxXor.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-22 09:51
# Description:

View File

@ -3,7 +3,7 @@
# File : trie.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:06
# Description:

View File

@ -4,7 +4,7 @@
# File : accountsMerge.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-18 17:07
# Description:

View File

@ -4,7 +4,7 @@
# File : unionFind.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-18 14:53
# Description:

View File

@ -3,7 +3,7 @@
# File : winnerTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:06
# Description:

View File

@ -3,7 +3,7 @@
# File : min_distance_of_n_points.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-24 22:03
# Description:

View File

@ -1,6 +1,6 @@
# 算法笔记
>注意, 目前 github 上的文档不支持 latex 数学公式渲染
所以如果想有较好的阅读体验, 可以移步到[我的博客](https://mbinary.coding.me)
所以如果想有较好的阅读体验, 可以移步到[我的博客](https://mbinary.xyz)
# 索引
* [.](.)

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +1,170 @@
---
title: 『数据结构』Fibonacci-heap
date: 2018-09-06 19:09
categories: 数据结构与算法
tags: [数据结构,斐波那契堆]
keywords: 数据结构,斐波那契堆
mathjax: true
description:
---
<!-- TOC -->
- [1. 结构](#1-结构)
- [2. 势函数](#2-势函数)
- [3. 最大度数](#3-最大度数)
- [4. 操作](#4-操作)
- [4.1. 创建一个斐波那契堆](#41-创建一个斐波那契堆)
- [4.2. 插入一个结点](#42-插入一个结点)
- [4.3. 寻找最小结点](#43-寻找最小结点)
- [4.4. 合并两个斐波那契堆](#44-合并两个斐波那契堆)
- [4.5. 抽取最小值](#45-抽取最小值)
- [4.6. 关键字减值](#46-关键字减值)
- [4.7. 删除结点](#47-删除结点)
- [5. 最大度数的证明](#5-最大度数的证明)
<!-- /TOC -->
![](https://upload-images.jianshu.io/upload_images/7130568-22531846a72b0d83.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-1-结构" name="1-结构"></a>
# 1. 结构
斐波那契堆是一系列具有最小堆序的有根树的集合, 同一代(层)结点由双向循环链表链接, **为了便于删除最小结点, 还需要维持链表为升序, 即nd<=nd.right(nd==nd.right时只有一个结点或为 None)**, 父子之间都有指向对方的指针.
结点有degree 属性, 记录孩子的个数, mark 属性用来标记(为了满足势函数, 达到摊还需求的)
还有一个最小值指针 H.min 指向最小根结点
![](https://upload-images.jianshu.io/upload_images/7130568-d4e8a85754fdbc14.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-2-势函数" name="2-势函数"></a>
# 2. 势函数
下面用势函数来分析摊还代价, 如果你不明白, 可以看[摊还分析](https://www.jianshu.com/p/052fbe9d92a4)
$\Phi(H) = t(H) + 2m(h)$
t 是根链表中树的数目,m(H) 表示被标记的结点数
最初没有结点
<a id="markdown-3-最大度数" name="3-最大度数"></a>
# 3. 最大度数
结点的最大度数(即孩子数)$D(n)\leqslant \lfloor lgn \rfloor$, 证明放在最后
<a id="markdown-4-操作" name="4-操作"></a>
# 4. 操作
<a id="markdown-41-创建一个斐波那契堆" name="41-创建一个斐波那契堆"></a>
## 4.1. 创建一个斐波那契堆
$O(1)$
<a id="markdown-42-插入一个结点" name="42-插入一个结点"></a>
## 4.2. 插入一个结点
```python
nd = new node
nd.prt = nd.chd = None
if H.min is None:
creat H with nd
H.min = nd
else:
insert nd into H's root list
if H.min<nd: H.min = nd
H.n +=1
```
$$
\Delta \Phi = \Delta t(H) + 2\Delta m(H) = 1+0 = 1
$$
摊还代价为$O(1)$
<a id="markdown-43-寻找最小结点" name="43-寻找最小结点"></a>
## 4.3. 寻找最小结点
直接用 H.min, $O(1)$
<a id="markdown-44-合并两个斐波那契堆" name="44-合并两个斐波那契堆"></a>
## 4.4. 合并两个斐波那契堆
```python
def union(H1,H2):
if H1.min ==None or (H1.min and H2.min and H1.min>H2.min):
H1.min = H2.min
link H2.rootList to H1.rootList
return H1
```
易知 $\Delta \Phi = 0$
<a id="markdown-45-抽取最小值" name="45-抽取最小值"></a>
## 4.5. 抽取最小值
抽取最小值, 一定是在根结点, 然后将此根结点的所有子树的根放在 根结点双向循环链表中, 之后还要进行**树的合并. 以使每个根结点的度不同,**
```python
def extract-min(H):
z = H.min
if z!=None:
for chd of z:
link chd to H.rootList
chd.prt = None
remove z from the rootList of H
if z==z.right:
H.min = None
else:
H.min = z.right
consolidate(H)
H.n -=1
return z
```
consolidate 函数使用一个 辅助数组degree来记录所有根结点(不超过lgn)对应的度数, degree[i] = nd 表示.有且只有一个结点 nd 的度数为 i.
```python
def consolidate(H):
initialize degree with None
for nd in H.rootList:
d = nd.degree
while degree[d] !=None:
nd2 = degree[d]
if nd2.degree < nd.degree:
nd2,nd = nd,nd2
make nd2 child of nd
nd.degree = d+1
nd.mark = False # to balace the potential
remove nd2 from H.rootList
degree[d] = None
d+=1
else: degree[d] = nd
for i in degree:
if i!=None:
link i to H.rootList
if H.min ==None: H.min = i
else if H.min>i: H.min = i
```
时间复杂度为$O(lgn)$ 即数组移动的长度, 而最多有 lgn个元素
<a id="markdown-46-关键字减值" name="46-关键字减值"></a>
## 4.6. 关键字减值
```python
def decrease-key(H,x,k):
if k>x.key: error
x.key = k
y=x.p
if y!=None and x.key < y.key:
cut(H,x,y)
cascading-cut(H,y)
if x.key < H.min.key:
H.min = x
def cut(H,x,y):
remove x from the child list of y, decrementing y.degree
add x to H.rootList
x.prt = None
x.mark = False
def cascading-cut(H,y):
z- y,prt
if z !=None:
if y.mark ==False:y.mark = True
else:
cut(H,y,z)
cascading-cut(H,z)
```
![](https://upload-images.jianshu.io/upload_images/7130568-0a29221f8a1fbfbb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-47-删除结点" name="47-删除结点"></a>
## 4.7. 删除结点
```python
decrease(H,nd, MIN)
extract-min(H)
```
<a id="markdown-5-最大度数的证明" name="5-最大度数的证明"></a>
# 5. 最大度数的证明
这也是`斐波那契`这个名字的由来,
$D(n)\leqslant \lfloor lgn \rfloor$
![](https://upload-images.jianshu.io/upload_images/7130568-c9e0cd3be4e98c4b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
---
title: 『数据结构』Fibonacci-heap
date: 2018-09-06 19:09
categories: 数据结构与算法
tags: [数据结构,斐波那契堆]
keywords: 数据结构,斐波那契堆
mathjax: true
description:
---
<!-- TOC -->
- [1. 结构](#1-结构)
- [2. 势函数](#2-势函数)
- [3. 最大度数](#3-最大度数)
- [4. 操作](#4-操作)
- [4.1. 创建一个斐波那契堆](#41-创建一个斐波那契堆)
- [4.2. 插入一个结点](#42-插入一个结点)
- [4.3. 寻找最小结点](#43-寻找最小结点)
- [4.4. 合并两个斐波那契堆](#44-合并两个斐波那契堆)
- [4.5. 抽取最小值](#45-抽取最小值)
- [4.6. 关键字减值](#46-关键字减值)
- [4.7. 删除结点](#47-删除结点)
- [5. 最大度数的证明](#5-最大度数的证明)
<!-- /TOC -->
![](https://upload-images.jianshu.io/upload_images/7130568-22531846a72b0d83.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-1-结构" name="1-结构"></a>
# 1. 结构
斐波那契堆是一系列具有最小堆序的有根树的集合, 同一代(层)结点由双向循环链表链接, **为了便于删除最小结点, 还需要维持链表为升序, 即nd<=nd.right(nd==nd.right时只有一个结点或为 None)**, 父子之间都有指向对方的指针.
结点有degree 属性, 记录孩子的个数, mark 属性用来标记(为了满足势函数, 达到摊还需求的)
还有一个最小值指针 H.min 指向最小根结点
![](https://upload-images.jianshu.io/upload_images/7130568-d4e8a85754fdbc14.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-2-势函数" name="2-势函数"></a>
# 2. 势函数
下面用势函数来分析摊还代价, 如果你不明白, 可以看[摊还分析](https://www.jianshu.com/p/052fbe9d92a4)
$\Phi(H) = t(H) + 2m(h)$
t 是根链表中树的数目,m(H) 表示被标记的结点数
最初没有结点
<a id="markdown-3-最大度数" name="3-最大度数"></a>
# 3. 最大度数
结点的最大度数(即孩子数)$D(n)\leqslant \lfloor lgn \rfloor$, 证明放在最后
<a id="markdown-4-操作" name="4-操作"></a>
# 4. 操作
<a id="markdown-41-创建一个斐波那契堆" name="41-创建一个斐波那契堆"></a>
## 4.1. 创建一个斐波那契堆
$O(1)$
<a id="markdown-42-插入一个结点" name="42-插入一个结点"></a>
## 4.2. 插入一个结点
```python
nd = new node
nd.prt = nd.chd = None
if H.min is None:
creat H with nd
H.min = nd
else:
insert nd into H's root list
if H.min<nd: H.min = nd
H.n +=1
```
$$
\Delta \Phi = \Delta t(H) + 2\Delta m(H) = 1+0 = 1
$$
摊还代价为$O(1)$
<a id="markdown-43-寻找最小结点" name="43-寻找最小结点"></a>
## 4.3. 寻找最小结点
直接用 H.min, $O(1)$
<a id="markdown-44-合并两个斐波那契堆" name="44-合并两个斐波那契堆"></a>
## 4.4. 合并两个斐波那契堆
```python
def union(H1,H2):
if H1.min ==None or (H1.min and H2.min and H1.min>H2.min):
H1.min = H2.min
link H2.rootList to H1.rootList
return H1
```
易知 $\Delta \Phi = 0$
<a id="markdown-45-抽取最小值" name="45-抽取最小值"></a>
## 4.5. 抽取最小值
抽取最小值, 一定是在根结点, 然后将此根结点的所有子树的根放在 根结点双向循环链表中, 之后还要进行**树的合并. 以使每个根结点的度不同,**
```python
def extract-min(H):
z = H.min
if z!=None:
for chd of z:
link chd to H.rootList
chd.prt = None
remove z from the rootList of H
if z==z.right:
H.min = None
else:
H.min = z.right
consolidate(H)
H.n -=1
return z
```
consolidate 函数使用一个 辅助数组degree来记录所有根结点(不超过lgn)对应的度数, degree[i] = nd 表示.有且只有一个结点 nd 的度数为 i.
```python
def consolidate(H):
initialize degree with None
for nd in H.rootList:
d = nd.degree
while degree[d] !=None:
nd2 = degree[d]
if nd2.degree < nd.degree:
nd2,nd = nd,nd2
make nd2 child of nd
nd.degree = d+1
nd.mark = False # to balace the potential
remove nd2 from H.rootList
degree[d] = None
d+=1
else: degree[d] = nd
for i in degree:
if i!=None:
link i to H.rootList
if H.min ==None: H.min = i
else if H.min>i: H.min = i
```
时间复杂度为$O(lgn)$ 即数组移动的长度, 而最多有 lgn个元素
<a id="markdown-46-关键字减值" name="46-关键字减值"></a>
## 4.6. 关键字减值
```python
def decrease-key(H,x,k):
if k>x.key: error
x.key = k
y=x.p
if y!=None and x.key < y.key:
cut(H,x,y)
cascading-cut(H,y)
if x.key < H.min.key:
H.min = x
def cut(H,x,y):
remove x from the child list of y, decrementing y.degree
add x to H.rootList
x.prt = None
x.mark = False
def cascading-cut(H,y):
z- y,prt
if z !=None:
if y.mark ==False:y.mark = True
else:
cut(H,y,z)
cascading-cut(H,z)
```
![](https://upload-images.jianshu.io/upload_images/7130568-0a29221f8a1fbfbb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-47-删除结点" name="47-删除结点"></a>
## 4.7. 删除结点
```python
decrease(H,nd, MIN)
extract-min(H)
```
<a id="markdown-5-最大度数的证明" name="5-最大度数的证明"></a>
# 5. 最大度数的证明
这也是`斐波那契`这个名字的由来,
$D(n)\leqslant \lfloor lgn \rfloor$
![](https://upload-images.jianshu.io/upload_images/7130568-c9e0cd3be4e98c4b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

View File

@ -1,474 +1,474 @@
---
title: 图算法
date: 2018-09-06 19:10
categories: 数据结构与算法
tags: [图,算法]
keywords: 图,算法
mathjax: true
description:
---
<!-- TOC -->
- [1. 图](#1-图)
- [1.1. 概念](#11-概念)
- [1.1.1. 性质](#111-性质)
- [1.2. 图的表示](#12-图的表示)
- [1.3. 树](#13-树)
- [2. 搜索](#2-搜索)
- [2.1. BFS](#21-bfs)
- [2.2. DFS](#22-dfs)
- [2.2.1. DFS 的性质](#221-dfs-的性质)
- [2.3. 拓扑排序](#23-拓扑排序)
- [2.4. 强连通分量](#24-强连通分量)
- [3. 最小生成树](#3-最小生成树)
- [3.1. Kruskal 算法](#31-kruskal-算法)
- [3.2. Prim 算法](#32-prim-算法)
- [4. 单源最短路](#4-单源最短路)
- [4.1. 负权重的边](#41-负权重的边)
- [4.2. 初始化](#42-初始化)
- [4.3. 松弛操作](#43-松弛操作)
- [4.4. 有向无环图的单源最短路问题](#44-有向无环图的单源最短路问题)
- [4.5. Bellman-Ford 算法](#45-bellman-ford-算法)
- [4.6. Dijkstra 算法](#46-dijkstra-算法)
- [5. 所有结点对的最短路问题](#5-所有结点对的最短路问题)
- [5.1. 矩阵乘法](#51-矩阵乘法)
- [5.2. Floyd-Warshall 算法](#52-floyd-warshall-算法)
- [5.3. Johnson 算法](#53-johnson-算法)
- [6. 最大流](#6-最大流)
- [6.1. 定理](#61-定理)
- [6.2. 多个源,汇](#62-多个源汇)
- [6.3. Ford-Fulkerson 方法](#63-ford-fulkerson-方法)
- [6.3.1. 残存网络](#631-残存网络)
- [6.3.2. 增广路径](#632-增广路径)
- [6.3.3. 割](#633-割)
- [6.4. 基本的 Ford-Fulkerson算法](#64-基本的-ford-fulkerson算法)
- [6.5. TBD](#65-tbd)
- [7. 参考资料](#7-参考资料)
<!-- /TOC -->
<a id="markdown-1-图" name="1-图"></a>
# 1. 图
<a id="markdown-11-概念" name="11-概念"></a>
## 1.1. 概念
* 顶
* 顶点的度 d
* 边
* 相邻
* 重边
* 环
* 完全图: 所有顶都相邻
* 二分图: $V(G) = X \cup Y, X\cap Y = \varnothing$, X中, Y 中任两顶不相邻
* 轨道
* 圈
<a id="markdown-111-性质" name="111-性质"></a>
### 1.1.1. 性质
* $\sum_{v\in V} d(v) = 2|E|$
* G是二分图 $\Leftrightarrow$ G无奇圈
* 树是无圈连通图
* 树中, $|E| = |V| -1$
<a id="markdown-12-图的表示" name="12-图的表示"></a>
## 1.2. 图的表示
* 邻接矩阵
* 邻接链表
![](https://upload-images.jianshu.io/upload_images/7130568-57ce6db904992656.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-13-树" name="13-树"></a>
## 1.3. 树
无圈连通图, $E = V-1$, 详细见[树](https://mbinary.coding.me/tree.html),
<a id="markdown-2-搜索" name="2-搜索"></a>
# 2. 搜索
求图的生成树[^1]
<a id="markdown-21-bfs" name="21-bfs"></a>
## 2.1. BFS
```python
for v in V:
v.d = MAX
v.pre = None
v.isFind = False
root. isFind = True
root.d = 0
que = [root]
while que !=[]:
nd = que.pop(0)
for v in Adj(nd):
if not v.isFind :
v.d = nd.d+1
v.pre = nd
v.isFind = True
que.append(v)
```
时间复杂度 $O(V+E)$
<a id="markdown-22-dfs" name="22-dfs"></a>
## 2.2. DFS
$\Theta(V+E)$
```python
def dfs(G):
time = 0
for v in V:
v.pre = None
v.isFind = False
for v in V : # note this,
if not v.isFind:
dfsVisit(v)
def dfsVisit(G,u):
time =time+1
u.begin = time
u.isFind = True
for v in Adj(u):
if not v.isFind:
v.pre = u
dfsVisit(G,v)
time +=1
u.end = time
```
begin, end 分别是结点的发现时间与完成时间
<a id="markdown-221-dfs-的性质" name="221-dfs-的性质"></a>
### 2.2.1. DFS 的性质
* 其生成的前驱子图$G_{pre}$ 形成一个由多棵树构成的森林, 这是因为其与 dfsVisit 的递归调用树相对应
* 括号化结构
![](https://upload-images.jianshu.io/upload_images/7130568-ba62e68e5b883b6c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 括号化定理:
考察两个结点的发现时间与结束时间的区间 [u,begin,u.end] 与 [v.begin,v.end]
* 如果两者没有交集, 则两个结点在两个不同的子树上(递归树)
* 如果 u 的区间包含在 v 的区间, 则 u 是v 的后代
<a id="markdown-23-拓扑排序" name="23-拓扑排序"></a>
## 2.3. 拓扑排序
利用 DFS, 结点的完成时间的逆序就是拓扑排序
同一个图可能有不同的拓扑排序
<a id="markdown-24-强连通分量" name="24-强连通分量"></a>
## 2.4. 强连通分量
在有向图中, 强连通分量中的结点互达
定义 $Grev$ 为 $G$ 中所有边反向后的图
将图分解成强连通分量的算法
在 Grev 上根据 G 中结点的拓扑排序来 dfsVisit, 即
```python
compute Grev
initalization
for v in topo-sort(G.V):
if not v.isFind: dfsVisit(Grev,v)
```
然后得到的DFS 森林(也是递归树森林)中每个树就是一个强连通分量
<a id="markdown-3-最小生成树" name="3-最小生成树"></a>
# 3. 最小生成树
利用了贪心算法,
<a id="markdown-31-kruskal-算法" name="31-kruskal-算法"></a>
## 3.1. Kruskal 算法
总体上, 从最开始 每个结点就是一颗树的森林中(不相交集合, 并查集), 逐渐添加不形成圈的(两个元素不再同一个集合),最小边权的边.
```python
edges=[]
for edge as u,v in sorted(G.E):
if find-set(u) != find-set(v):
edges.append(edge)
union(u,v)
return edges
```
如果并查集的实现采用了 按秩合并与路径压缩技巧, 则 find 与 union 的时间接近常数
所以时间复杂度在于排序边, 即 $O(ElgE)$, 而 $ E\< V^2 $, 所以 $lgE = O(lgV)$, 时间复杂度为 $O(ElgV)$
<a id="markdown-32-prim-算法" name="32-prim-算法"></a>
## 3.2. Prim 算法
用了 BFS, 类似 Dijkstra 算法
从根结点开始 BFS, 一直保持成一颗树
```python
for v in V:
v.minAdjEdge = MAX
v.pre = None
root.minAdjEdge = 0
que = priority-queue (G.V) # sort by minAdjEdge
while not que.isempty():
u = que.extractMin()
for v in Adj(u):
if v in que and v.minAdjEdge>w(u,v):
v.pre = u
v.minAdjEdge = w(u,v)
```
* 建堆 $O(V)$ `//note it's v, not vlgv`
* 主循环中
* extractMin: $O(VlgV)$
* in 操作 可以另设标志位, 在常数时间完成, 总共 $O(E)$
* 设置结点的 minAdjEdge, 需要$O(lgv)$, 循环 E 次,则 总共$O(ElgV)$
综上, 时间复杂度为$O(ElgV)$
如果使用的是 [斐波那契堆](https://mbinary.coding.me/fib-heap.html), 则可改进到 $O(E+VlgV)$
<a id="markdown-4-单源最短路" name="4-单源最短路"></a>
# 4. 单源最短路
求一个结点到其他结点的最短路径, 可以用 Bellman-Ford算法, 或者 Dijkstra算法.
定义两个结点u,v间的最短路
$$
\delta(u,v) = \begin{cases}
min(w(path)),\quad u\xrightarrow{path} v\\
MAX, \quad u\nrightarrow v
\end{cases}
$$
问题的变体
* 单目的地最短路问题: 可以将所有边反向转换成求单源最短路问题
* 单结点对的最短路径
* 所有结点对最短路路径
<a id="markdown-41-负权重的边" name="41-负权重的边"></a>
## 4.1. 负权重的边
Dijkstra 算法不能处理负权边, 只能用 Bellman-Ford 算法,
而且如果有负值圈, 则没有最短路, bellman-ford算法也可以检测出来
<a id="markdown-42-初始化" name="42-初始化"></a>
## 4.2. 初始化
```python
def initialaize(G,s):
for v in G.V:
v.pre = None
v.distance = MAX
s.distance = 0
```
<a id="markdown-43-松弛操作" name="43-松弛操作"></a>
## 4.3. 松弛操作
```python
def relax(u,v,w):
if v.distance > u.distance + w:
v.distance = u.distance + w:
v.pre = u
```
性质
* 三角不等式: $\delta(s,v) \leqslant \delta(s,u) + w(u,v)$
* 上界: $v.distance \geqslant \delta(s,v)$
* 收敛: 对于某些结点u,v 如果s->...->u->v是图G中的一条最短路径并且在对边进行松弛前任意时间有 $u.distance=\delta(s,u)$则在之后的所有时间有 $v.distance=\delta(s,v)$
* 路径松弛性质: 如果$p=v_0 v_1 \ldots v_k$是从源结点下v0到结点vk的一条最短路径并且对p中的边所进行松弛的次序为$(v_0,v_1),(v_1,v_2), \ldots ,(v_{k-1},v_k)$, 则 $v_k.distance = \delta(s,v_k)$
该性质的成立与任何其他的松弛操作无关即使这些松弛操作是与对p上的边所进行的松弛操作穿插进行的。
证明
![](https://upload-images.jianshu.io/upload_images/7130568-424a6929bd389825.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-44-有向无环图的单源最短路问题" name="44-有向无环图的单源最短路问题"></a>
## 4.4. 有向无环图的单源最短路问题
```python
def dag-shortest-path(G,s):
initialize(G,s)
for u in topo-sort(G.V):
for v in Adj(v):
relax(u,v,w(u,v))
```
<a id="markdown-45-bellman-ford-算法" name="45-bellman-ford-算法"></a>
## 4.5. Bellman-Ford 算法
```python
def bellman-ford(G,s):
initialize(G,s)
for ct in range(|V|-1): # v-1times
for u,v as edge in E:
relax(u,v,w(u,v))
for u,v as edge in E:
if v.distance > u.distance + w(u,v):
return False
return True
```
第一个 for 循环就是进行松弛操作, 最后结果已经存储在 结点的distance 和 pre 属性中了, 第二个 for 循环利用三角不等式检查有不有负值圈.
下面是证明该算法的正确性![](https://upload-images.jianshu.io/upload_images/7130568-f84e00ac35aadc81.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-46-dijkstra-算法" name="46-dijkstra-算法"></a>
## 4.6. Dijkstra 算法
```python
def dijkstra(G,s):
initialize(G,s)
paths=[]
q = priority-queue(G.V) # sort by distance
while not q.empty():
u = q.extract-min()
paths.append(u)
for v in Adj(u):
relax(u,v,w(u,v))
```
<a id="markdown-5-所有结点对的最短路问题" name="5-所有结点对的最短路问题"></a>
# 5. 所有结点对的最短路问题
<a id="markdown-51-矩阵乘法" name="51-矩阵乘法"></a>
## 5.1. 矩阵乘法
使用动态规划算法, 可以得到最短路径的结构
设 $l_{ij}^{(m)}$为从结点i 到结点 j 的至多包含 m 条边的任意路径的最小权重,当m = 0, 此时i=j, 则 为0,
可以得到递归定义
$$
l_{ij}^{(m)} =\min( l_{ij}^{(m-1)}, \min_{1\leqslant k\leqslant n}( l_{ik}^{(m-1)}+w_{kj})) = \min_{1\leqslant k\leqslant n}( l_{ik}^{(m-1)}+w_{kj}))
$$
由于是简单路径, 则包含的边最多为 |V|-1 条, 所以
$$
\delta(i,j) = l_{ij}^{(|V|-1)} = l_{ij}^{(|V|)} =l_{ij}^{(|V| + 1)}= ...
$$
所以可以自底向上计算, 如下
输入权值矩阵 $W(w_{ij})), L^{(m-1)}$,输出$ L^{(m)}$, 其中 $L^{(1)} = W$,
```python
n = L.rows
L' = new matrix(nxn)
for i in range(n):
for j in range(n):
l'[i][j] = MAX
for k in range(n):
l'[i][j] = min(l'[i][j], l[i][k]+w[k][j])
return L'
```
可以看出该算法与矩阵乘法的关系
$L^{(m)} = W^m$,
所以可以直接计算乘法, 每次计算一个乘积是 $O(V^3)$, 计算 V 次, 所以总体 $O(V^4)$, 使用矩阵快速幂可以将时间复杂度降低为$O(V^3lgV)$
```python
def f(W):
L = W
i = 1
while i<W.rows:
L = L*L
i*=2
return L
```
<a id="markdown-52-floyd-warshall-算法" name="52-floyd-warshall-算法"></a>
## 5.2. Floyd-Warshall 算法
同样要求可以存在负权边, 但不能有负值圈. 用动态规划算法:
设 $ d_{ij}^{(k)}$ 为 从 i 到 j 所有中间结点来自集合 ${\{1,2,\ldots,k\}}$ 的一条最短路径的权重. 则有
$$
d_{ij}^{(k)} = \begin{cases}
w_{ij},\quad k=0\\
min(d_{ij}^{(k-1)},d_{ik}^{(k-1)}+d_{kj}^{(k-1)}),\quad k\geqslant 1
\end{cases}
$$
而且为了找出路径, 需要记录前驱结点, 定义如下前驱矩阵 $\Pi$, 设 $ \pi_{ij}^{(k)}$ 为 从 i 到 j 所有中间结点来自集合 ${\{1,2,\ldots,k\}}$ 的最短路径上 j 的前驱结点
$$
\pi_{ij}^{(0)} = \begin{cases}
nil,\quad i=j \ or \ w_{ij}=MAX\\
i, \quad i\neq j and \ w_{ij}<MAX
\end{cases}
$$
对 $k\geqslant 1$
$$
\pi_{ij}^{(k)} = \begin{cases}
\pi_{ij}^{(k-1)} ,\quad d_{ij}^{(k-1)}\leqslant d_{ik}^{(k-1)}+d_{kj}^{(k-1)}\\
\pi_{kj}^{(k-1)} ,\quad otherwise
\end{cases}
$$
由此得出此算法
```python
def floyd-warshall(w):
n = len(w)
d= w
initial pre # 0
for k in range(n):
d2 = d.copy()
pre2 = pre.copy()
for j in range(n):
for i in range(v)
if d[i][j] > d[i][k]+d[k][j]:
d2[i][j] = min(d[i][j], d[i][k]+d[k][j])
pre2[i][j] = pre[k][j]
pre = pre2
d = d2
return d,pre
```
<a id="markdown-53-johnson-算法" name="53-johnson-算法"></a>
## 5.3. Johnson 算法
思路是通过重新赋予权重, 将图中负权边转换为正权,然后就可以用 dijkstra 算法(要求是正值边)来计算一个结点到其他所有结点的, 然后对所有结点用dijkstra
1. 首先构造一个新图 G'
先将G拷贝到G', 再添加一个新结点 s, 添加 G.V条边, s 到G中顶点的, 权赋值为 0
2. 用 Bellman-Ford 算法检查是否有负值圈, 如果没有, 同时求出 $\delta(s,v) 记为 h(v)$
3. 求新的非负值权, w'(u,v) = w(u,v)+h(u)-h(v)
4. 对所有结点在 新的权矩阵w'上 用 Dijkstra 算法
![image.png](https://upload-images.jianshu.io/upload_images/7130568-6c2146ad64d692f3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
```python
JOHNSON (G, u)
s = newNode
G' = G.copy()
G'.addNode(s)
for v in G.V: G'.addArc(s,v,w=0)
if BELLMAN-FORD(G' , w, s) ==FALSE
error "the input graph contains a negative-weight cycle"
for v in G'.V:
# computed by the bellman-ford algorithm, delta(s,v) is the shortest distance from s to v
h(v) = delta(s,v)
for edge(u,v) in G'.E:
w' = w(u,v)+h(u)-h(v)
d = matrix(n,n)
for u in G:
dijkstra(G,w',u) # compute delta' for all v in G.V
for v in G.V:
d[u][v] = delta'(u,v) + h(v)-h(u)
return d
```
<a id="markdown-6-最大流" name="6-最大流"></a>
# 6. 最大流
G 是弱连通严格有向加权图, s为源, t 为汇, 每条边e容量 c(e), 由此定义了网络N(G,s,t,c(e)),
* 流函数 $f(e):E \rightarrow R$
$$
\begin{aligned}
(1)\quad & 0\leqslant f(e) \leqslant c(e),\quad e \in E\\
(2)\quad & \sum_{e\in \alpha(v)} f(e)= \sum_{e\in \beta(v)}f(e),\quad v \in V-\{s,t\}
\end{aligned}
$$
其中 $\alpha(v)$ 是以 v 为头的边集, $\beta(v)$是以 v 为尾的边集
* 流量: $F = \sum_{e\in \alpha(t)} f(e)- \sum_{e\in -\beta(t)}f(e),$
* 截$(S,\overline S)$: $S\subset V,s\in S, t\in \overline S =V-S$
* 截量$C(S) = \sum_{e\in(S,\overline S)}c(e)$
<a id="markdown-61-定理" name="61-定理"></a>
## 6.1. 定理
参考 图论[^2]
* 对于任一截$(S,\overline S)$, 有 $F = \sum_{e\in (S,\overline S)} f(e)- \sum_{e\in(\overline S,S)}f(e),$
![prove](https://upload-images.jianshu.io/upload_images/7130568-19bf6cc3c7d6ce06.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* $F\leqslant C(S)$
证明: 由上面定理
$$F = \sum_{e\in (S,\overline S)} f(e)- \sum_{e\in(\overline S,S)}f(e),$$
而 $0\leqslant f(e) \leqslant c(e)$, 则
$$F\leqslant \sum_{e\in (S,\overline S)} f(e) \leqslant \sum_{e\in (S,\overline S)} c(e) = C(S) $$
* 最大流,最小截: 若$F= C(S) $, 则F'是最大流量, C(S) 是最小截量
<a id="markdown-62-多个源汇" name="62-多个源汇"></a>
## 6.2. 多个源,汇
可以新增一个总的源,一个总的汇,
![](https://upload-images.jianshu.io/upload_images/7130568-3e9e87fdf9655883.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-63-ford-fulkerson-方法" name="63-ford-fulkerson-方法"></a>
## 6.3. Ford-Fulkerson 方法
由于其实现可以有不同的运行时间, 所以称其为方法, 而不是算法.
思路是 循环增加流的值, 在一个关联的"残存网络" 中寻找一条"增广路径", 然后对这些边进行修改流量. 重复直至残存网络上不再存在增高路径为止.
```python
def ford-fulkerson(G,s,t):
initialize flow f to 0
while exists an augmenting path p in residual network Gf:
augment flow f along p
return f
```
<a id="markdown-631-残存网络" name="631-残存网络"></a>
### 6.3.1. 残存网络
![](https://upload-images.jianshu.io/upload_images/7130568-c74a571b9121dbbf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-632-增广路径" name="632-增广路径"></a>
### 6.3.2. 增广路径
![](https://upload-images.jianshu.io/upload_images/7130568-b9e841cfa4d04b57.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-633-割" name="633-割"></a>
### 6.3.3. 割
![](https://upload-images.jianshu.io/upload_images/7130568-74b065e86eb285b7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-64-基本的-ford-fulkerson算法" name="64-基本的-ford-fulkerson算法"></a>
## 6.4. 基本的 Ford-Fulkerson算法
```python
def ford-fulkerson(G,s,t):
for edge in G.E: edge.f = 0
while exists path p:s->t in Gf:
cf(p) = min{cf(u,v):(u,v) is in p}
for edge in p:
if edge in E:
edge.f +=cf(p)
else: reverse_edge.f -=cf(p)
```
<a id="markdown-65-tbd" name="65-tbd"></a>
## 6.5. TBD
<a id="markdown-7-参考资料" name="7-参考资料"></a>
# 7. 参考资料
[^1]: 算法导论
[^2]: 图论, 王树禾
---
title: 图算法
date: 2018-09-06 19:10
categories: 数据结构与算法
tags: [图,算法]
keywords: 图,算法
mathjax: true
description:
---
<!-- TOC -->
- [1. 图](#1-图)
- [1.1. 概念](#11-概念)
- [1.1.1. 性质](#111-性质)
- [1.2. 图的表示](#12-图的表示)
- [1.3. 树](#13-树)
- [2. 搜索](#2-搜索)
- [2.1. BFS](#21-bfs)
- [2.2. DFS](#22-dfs)
- [2.2.1. DFS 的性质](#221-dfs-的性质)
- [2.3. 拓扑排序](#23-拓扑排序)
- [2.4. 强连通分量](#24-强连通分量)
- [3. 最小生成树](#3-最小生成树)
- [3.1. Kruskal 算法](#31-kruskal-算法)
- [3.2. Prim 算法](#32-prim-算法)
- [4. 单源最短路](#4-单源最短路)
- [4.1. 负权重的边](#41-负权重的边)
- [4.2. 初始化](#42-初始化)
- [4.3. 松弛操作](#43-松弛操作)
- [4.4. 有向无环图的单源最短路问题](#44-有向无环图的单源最短路问题)
- [4.5. Bellman-Ford 算法](#45-bellman-ford-算法)
- [4.6. Dijkstra 算法](#46-dijkstra-算法)
- [5. 所有结点对的最短路问题](#5-所有结点对的最短路问题)
- [5.1. 矩阵乘法](#51-矩阵乘法)
- [5.2. Floyd-Warshall 算法](#52-floyd-warshall-算法)
- [5.3. Johnson 算法](#53-johnson-算法)
- [6. 最大流](#6-最大流)
- [6.1. 定理](#61-定理)
- [6.2. 多个源,汇](#62-多个源汇)
- [6.3. Ford-Fulkerson 方法](#63-ford-fulkerson-方法)
- [6.3.1. 残存网络](#631-残存网络)
- [6.3.2. 增广路径](#632-增广路径)
- [6.3.3. 割](#633-割)
- [6.4. 基本的 Ford-Fulkerson算法](#64-基本的-ford-fulkerson算法)
- [6.5. TBD](#65-tbd)
- [7. 参考资料](#7-参考资料)
<!-- /TOC -->
<a id="markdown-1-图" name="1-图"></a>
# 1. 图
<a id="markdown-11-概念" name="11-概念"></a>
## 1.1. 概念
* 顶
* 顶点的度 d
* 边
* 相邻
* 重边
* 环
* 完全图: 所有顶都相邻
* 二分图: $V(G) = X \cup Y, X\cap Y = \varnothing$, X中, Y 中任两顶不相邻
* 轨道
* 圈
<a id="markdown-111-性质" name="111-性质"></a>
### 1.1.1. 性质
* $\sum_{v\in V} d(v) = 2|E|$
* G是二分图 $\Leftrightarrow$ G无奇圈
* 树是无圈连通图
* 树中, $|E| = |V| -1$
<a id="markdown-12-图的表示" name="12-图的表示"></a>
## 1.2. 图的表示
* 邻接矩阵
* 邻接链表
![](https://upload-images.jianshu.io/upload_images/7130568-57ce6db904992656.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-13-树" name="13-树"></a>
## 1.3. 树
无圈连通图, $E = V-1$, 详细见[树](https://mbinary.xyz/tree.html),
<a id="markdown-2-搜索" name="2-搜索"></a>
# 2. 搜索
求图的生成树[^1]
<a id="markdown-21-bfs" name="21-bfs"></a>
## 2.1. BFS
```python
for v in V:
v.d = MAX
v.pre = None
v.isFind = False
root. isFind = True
root.d = 0
que = [root]
while que !=[]:
nd = que.pop(0)
for v in Adj(nd):
if not v.isFind :
v.d = nd.d+1
v.pre = nd
v.isFind = True
que.append(v)
```
时间复杂度 $O(V+E)$
<a id="markdown-22-dfs" name="22-dfs"></a>
## 2.2. DFS
$\Theta(V+E)$
```python
def dfs(G):
time = 0
for v in V:
v.pre = None
v.isFind = False
for v in V : # note this,
if not v.isFind:
dfsVisit(v)
def dfsVisit(G,u):
time =time+1
u.begin = time
u.isFind = True
for v in Adj(u):
if not v.isFind:
v.pre = u
dfsVisit(G,v)
time +=1
u.end = time
```
begin, end 分别是结点的发现时间与完成时间
<a id="markdown-221-dfs-的性质" name="221-dfs-的性质"></a>
### 2.2.1. DFS 的性质
* 其生成的前驱子图$G_{pre}$ 形成一个由多棵树构成的森林, 这是因为其与 dfsVisit 的递归调用树相对应
* 括号化结构
![](https://upload-images.jianshu.io/upload_images/7130568-ba62e68e5b883b6c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 括号化定理:
考察两个结点的发现时间与结束时间的区间 [u,begin,u.end] 与 [v.begin,v.end]
* 如果两者没有交集, 则两个结点在两个不同的子树上(递归树)
* 如果 u 的区间包含在 v 的区间, 则 u 是v 的后代
<a id="markdown-23-拓扑排序" name="23-拓扑排序"></a>
## 2.3. 拓扑排序
利用 DFS, 结点的完成时间的逆序就是拓扑排序
同一个图可能有不同的拓扑排序
<a id="markdown-24-强连通分量" name="24-强连通分量"></a>
## 2.4. 强连通分量
在有向图中, 强连通分量中的结点互达
定义 $Grev$ 为 $G$ 中所有边反向后的图
将图分解成强连通分量的算法
在 Grev 上根据 G 中结点的拓扑排序来 dfsVisit, 即
```python
compute Grev
initalization
for v in topo-sort(G.V):
if not v.isFind: dfsVisit(Grev,v)
```
然后得到的DFS 森林(也是递归树森林)中每个树就是一个强连通分量
<a id="markdown-3-最小生成树" name="3-最小生成树"></a>
# 3. 最小生成树
利用了贪心算法,
<a id="markdown-31-kruskal-算法" name="31-kruskal-算法"></a>
## 3.1. Kruskal 算法
总体上, 从最开始 每个结点就是一颗树的森林中(不相交集合, 并查集), 逐渐添加不形成圈的(两个元素不再同一个集合),最小边权的边.
```python
edges=[]
for edge as u,v in sorted(G.E):
if find-set(u) != find-set(v):
edges.append(edge)
union(u,v)
return edges
```
如果并查集的实现采用了 按秩合并与路径压缩技巧, 则 find 与 union 的时间接近常数
所以时间复杂度在于排序边, 即 $O(ElgE)$, 而 $ E\< V^2 $, 所以 $lgE = O(lgV)$, 时间复杂度为 $O(ElgV)$
<a id="markdown-32-prim-算法" name="32-prim-算法"></a>
## 3.2. Prim 算法
用了 BFS, 类似 Dijkstra 算法
从根结点开始 BFS, 一直保持成一颗树
```python
for v in V:
v.minAdjEdge = MAX
v.pre = None
root.minAdjEdge = 0
que = priority-queue (G.V) # sort by minAdjEdge
while not que.isempty():
u = que.extractMin()
for v in Adj(u):
if v in que and v.minAdjEdge>w(u,v):
v.pre = u
v.minAdjEdge = w(u,v)
```
* 建堆 $O(V)$ `//note it's v, not vlgv`
* 主循环中
* extractMin: $O(VlgV)$
* in 操作 可以另设标志位, 在常数时间完成, 总共 $O(E)$
* 设置结点的 minAdjEdge, 需要$O(lgv)$, 循环 E 次,则 总共$O(ElgV)$
综上, 时间复杂度为$O(ElgV)$
如果使用的是 [斐波那契堆](https://mbinary.xyz/fib-heap.html), 则可改进到 $O(E+VlgV)$
<a id="markdown-4-单源最短路" name="4-单源最短路"></a>
# 4. 单源最短路
求一个结点到其他结点的最短路径, 可以用 Bellman-Ford算法, 或者 Dijkstra算法.
定义两个结点u,v间的最短路
$$
\delta(u,v) = \begin{cases}
min(w(path)),\quad u\xrightarrow{path} v\\
MAX, \quad u\nrightarrow v
\end{cases}
$$
问题的变体
* 单目的地最短路问题: 可以将所有边反向转换成求单源最短路问题
* 单结点对的最短路径
* 所有结点对最短路路径
<a id="markdown-41-负权重的边" name="41-负权重的边"></a>
## 4.1. 负权重的边
Dijkstra 算法不能处理负权边, 只能用 Bellman-Ford 算法,
而且如果有负值圈, 则没有最短路, bellman-ford算法也可以检测出来
<a id="markdown-42-初始化" name="42-初始化"></a>
## 4.2. 初始化
```python
def initialaize(G,s):
for v in G.V:
v.pre = None
v.distance = MAX
s.distance = 0
```
<a id="markdown-43-松弛操作" name="43-松弛操作"></a>
## 4.3. 松弛操作
```python
def relax(u,v,w):
if v.distance > u.distance + w:
v.distance = u.distance + w:
v.pre = u
```
性质
* 三角不等式: $\delta(s,v) \leqslant \delta(s,u) + w(u,v)$
* 上界: $v.distance \geqslant \delta(s,v)$
* 收敛: 对于某些结点u,v 如果s->...->u->v是图G中的一条最短路径并且在对边进行松弛前任意时间有 $u.distance=\delta(s,u)$则在之后的所有时间有 $v.distance=\delta(s,v)$
* 路径松弛性质: 如果$p=v_0 v_1 \ldots v_k$是从源结点下v0到结点vk的一条最短路径并且对p中的边所进行松弛的次序为$(v_0,v_1),(v_1,v_2), \ldots ,(v_{k-1},v_k)$, 则 $v_k.distance = \delta(s,v_k)$
该性质的成立与任何其他的松弛操作无关即使这些松弛操作是与对p上的边所进行的松弛操作穿插进行的。
证明
![](https://upload-images.jianshu.io/upload_images/7130568-424a6929bd389825.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-44-有向无环图的单源最短路问题" name="44-有向无环图的单源最短路问题"></a>
## 4.4. 有向无环图的单源最短路问题
```python
def dag-shortest-path(G,s):
initialize(G,s)
for u in topo-sort(G.V):
for v in Adj(v):
relax(u,v,w(u,v))
```
<a id="markdown-45-bellman-ford-算法" name="45-bellman-ford-算法"></a>
## 4.5. Bellman-Ford 算法
```python
def bellman-ford(G,s):
initialize(G,s)
for ct in range(|V|-1): # v-1times
for u,v as edge in E:
relax(u,v,w(u,v))
for u,v as edge in E:
if v.distance > u.distance + w(u,v):
return False
return True
```
第一个 for 循环就是进行松弛操作, 最后结果已经存储在 结点的distance 和 pre 属性中了, 第二个 for 循环利用三角不等式检查有不有负值圈.
下面是证明该算法的正确性![](https://upload-images.jianshu.io/upload_images/7130568-f84e00ac35aadc81.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-46-dijkstra-算法" name="46-dijkstra-算法"></a>
## 4.6. Dijkstra 算法
```python
def dijkstra(G,s):
initialize(G,s)
paths=[]
q = priority-queue(G.V) # sort by distance
while not q.empty():
u = q.extract-min()
paths.append(u)
for v in Adj(u):
relax(u,v,w(u,v))
```
<a id="markdown-5-所有结点对的最短路问题" name="5-所有结点对的最短路问题"></a>
# 5. 所有结点对的最短路问题
<a id="markdown-51-矩阵乘法" name="51-矩阵乘法"></a>
## 5.1. 矩阵乘法
使用动态规划算法, 可以得到最短路径的结构
设 $l_{ij}^{(m)}$为从结点i 到结点 j 的至多包含 m 条边的任意路径的最小权重,当m = 0, 此时i=j, 则 为0,
可以得到递归定义
$$
l_{ij}^{(m)} =\min( l_{ij}^{(m-1)}, \min_{1\leqslant k\leqslant n}( l_{ik}^{(m-1)}+w_{kj})) = \min_{1\leqslant k\leqslant n}( l_{ik}^{(m-1)}+w_{kj}))
$$
由于是简单路径, 则包含的边最多为 |V|-1 条, 所以
$$
\delta(i,j) = l_{ij}^{(|V|-1)} = l_{ij}^{(|V|)} =l_{ij}^{(|V| + 1)}= ...
$$
所以可以自底向上计算, 如下
输入权值矩阵 $W(w_{ij})), L^{(m-1)}$,输出$ L^{(m)}$, 其中 $L^{(1)} = W$,
```python
n = L.rows
L' = new matrix(nxn)
for i in range(n):
for j in range(n):
l'[i][j] = MAX
for k in range(n):
l'[i][j] = min(l'[i][j], l[i][k]+w[k][j])
return L'
```
可以看出该算法与矩阵乘法的关系
$L^{(m)} = W^m$,
所以可以直接计算乘法, 每次计算一个乘积是 $O(V^3)$, 计算 V 次, 所以总体 $O(V^4)$, 使用矩阵快速幂可以将时间复杂度降低为$O(V^3lgV)$
```python
def f(W):
L = W
i = 1
while i<W.rows:
L = L*L
i*=2
return L
```
<a id="markdown-52-floyd-warshall-算法" name="52-floyd-warshall-算法"></a>
## 5.2. Floyd-Warshall 算法
同样要求可以存在负权边, 但不能有负值圈. 用动态规划算法:
设 $ d_{ij}^{(k)}$ 为 从 i 到 j 所有中间结点来自集合 ${\{1,2,\ldots,k\}}$ 的一条最短路径的权重. 则有
$$
d_{ij}^{(k)} = \begin{cases}
w_{ij},\quad k=0\\
min(d_{ij}^{(k-1)},d_{ik}^{(k-1)}+d_{kj}^{(k-1)}),\quad k\geqslant 1
\end{cases}
$$
而且为了找出路径, 需要记录前驱结点, 定义如下前驱矩阵 $\Pi$, 设 $ \pi_{ij}^{(k)}$ 为 从 i 到 j 所有中间结点来自集合 ${\{1,2,\ldots,k\}}$ 的最短路径上 j 的前驱结点
$$
\pi_{ij}^{(0)} = \begin{cases}
nil,\quad i=j \ or \ w_{ij}=MAX\\
i, \quad i\neq j and \ w_{ij}<MAX
\end{cases}
$$
对 $k\geqslant 1$
$$
\pi_{ij}^{(k)} = \begin{cases}
\pi_{ij}^{(k-1)} ,\quad d_{ij}^{(k-1)}\leqslant d_{ik}^{(k-1)}+d_{kj}^{(k-1)}\\
\pi_{kj}^{(k-1)} ,\quad otherwise
\end{cases}
$$
由此得出此算法
```python
def floyd-warshall(w):
n = len(w)
d= w
initial pre # 0
for k in range(n):
d2 = d.copy()
pre2 = pre.copy()
for j in range(n):
for i in range(v)
if d[i][j] > d[i][k]+d[k][j]:
d2[i][j] = min(d[i][j], d[i][k]+d[k][j])
pre2[i][j] = pre[k][j]
pre = pre2
d = d2
return d,pre
```
<a id="markdown-53-johnson-算法" name="53-johnson-算法"></a>
## 5.3. Johnson 算法
思路是通过重新赋予权重, 将图中负权边转换为正权,然后就可以用 dijkstra 算法(要求是正值边)来计算一个结点到其他所有结点的, 然后对所有结点用dijkstra
1. 首先构造一个新图 G'
先将G拷贝到G', 再添加一个新结点 s, 添加 G.V条边, s 到G中顶点的, 权赋值为 0
2. 用 Bellman-Ford 算法检查是否有负值圈, 如果没有, 同时求出 $\delta(s,v) 记为 h(v)$
3. 求新的非负值权, w'(u,v) = w(u,v)+h(u)-h(v)
4. 对所有结点在 新的权矩阵w'上 用 Dijkstra 算法
![image.png](https://upload-images.jianshu.io/upload_images/7130568-6c2146ad64d692f3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
```python
JOHNSON (G, u)
s = newNode
G' = G.copy()
G'.addNode(s)
for v in G.V: G'.addArc(s,v,w=0)
if BELLMAN-FORD(G' , w, s) ==FALSE
error "the input graph contains a negative-weight cycle"
for v in G'.V:
# computed by the bellman-ford algorithm, delta(s,v) is the shortest distance from s to v
h(v) = delta(s,v)
for edge(u,v) in G'.E:
w' = w(u,v)+h(u)-h(v)
d = matrix(n,n)
for u in G:
dijkstra(G,w',u) # compute delta' for all v in G.V
for v in G.V:
d[u][v] = delta'(u,v) + h(v)-h(u)
return d
```
<a id="markdown-6-最大流" name="6-最大流"></a>
# 6. 最大流
G 是弱连通严格有向加权图, s为源, t 为汇, 每条边e容量 c(e), 由此定义了网络N(G,s,t,c(e)),
* 流函数 $f(e):E \rightarrow R$
$$
\begin{aligned}
(1)\quad & 0\leqslant f(e) \leqslant c(e),\quad e \in E\\
(2)\quad & \sum_{e\in \alpha(v)} f(e)= \sum_{e\in \beta(v)}f(e),\quad v \in V-\{s,t\}
\end{aligned}
$$
其中 $\alpha(v)$ 是以 v 为头的边集, $\beta(v)$是以 v 为尾的边集
* 流量: $F = \sum_{e\in \alpha(t)} f(e)- \sum_{e\in -\beta(t)}f(e),$
* 截$(S,\overline S)$: $S\subset V,s\in S, t\in \overline S =V-S$
* 截量$C(S) = \sum_{e\in(S,\overline S)}c(e)$
<a id="markdown-61-定理" name="61-定理"></a>
## 6.1. 定理
参考 图论[^2]
* 对于任一截$(S,\overline S)$, 有 $F = \sum_{e\in (S,\overline S)} f(e)- \sum_{e\in(\overline S,S)}f(e),$
![prove](https://upload-images.jianshu.io/upload_images/7130568-19bf6cc3c7d6ce06.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* $F\leqslant C(S)$
证明: 由上面定理
$$F = \sum_{e\in (S,\overline S)} f(e)- \sum_{e\in(\overline S,S)}f(e),$$
而 $0\leqslant f(e) \leqslant c(e)$, 则
$$F\leqslant \sum_{e\in (S,\overline S)} f(e) \leqslant \sum_{e\in (S,\overline S)} c(e) = C(S) $$
* 最大流,最小截: 若$F= C(S) $, 则F'是最大流量, C(S) 是最小截量
<a id="markdown-62-多个源汇" name="62-多个源汇"></a>
## 6.2. 多个源,汇
可以新增一个总的源,一个总的汇,
![](https://upload-images.jianshu.io/upload_images/7130568-3e9e87fdf9655883.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-63-ford-fulkerson-方法" name="63-ford-fulkerson-方法"></a>
## 6.3. Ford-Fulkerson 方法
由于其实现可以有不同的运行时间, 所以称其为方法, 而不是算法.
思路是 循环增加流的值, 在一个关联的"残存网络" 中寻找一条"增广路径", 然后对这些边进行修改流量. 重复直至残存网络上不再存在增高路径为止.
```python
def ford-fulkerson(G,s,t):
initialize flow f to 0
while exists an augmenting path p in residual network Gf:
augment flow f along p
return f
```
<a id="markdown-631-残存网络" name="631-残存网络"></a>
### 6.3.1. 残存网络
![](https://upload-images.jianshu.io/upload_images/7130568-c74a571b9121dbbf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-632-增广路径" name="632-增广路径"></a>
### 6.3.2. 增广路径
![](https://upload-images.jianshu.io/upload_images/7130568-b9e841cfa4d04b57.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-633-割" name="633-割"></a>
### 6.3.3. 割
![](https://upload-images.jianshu.io/upload_images/7130568-74b065e86eb285b7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<a id="markdown-64-基本的-ford-fulkerson算法" name="64-基本的-ford-fulkerson算法"></a>
## 6.4. 基本的 Ford-Fulkerson算法
```python
def ford-fulkerson(G,s,t):
for edge in G.E: edge.f = 0
while exists path p:s->t in Gf:
cf(p) = min{cf(u,v):(u,v) is in p}
for edge in p:
if edge in E:
edge.f +=cf(p)
else: reverse_edge.f -=cf(p)
```
<a id="markdown-65-tbd" name="65-tbd"></a>
## 6.5. TBD
<a id="markdown-7-参考资料" name="7-参考资料"></a>
# 7. 参考资料
[^1]: 算法导论
[^2]: 图论, 王树禾

View File

@ -383,7 +383,7 @@ def find(root,i):
# File : redBlackTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-14 16:15
# Description:

View File

@ -215,7 +215,7 @@ Aho-Corasick automation,是在字典树上添加匹配失败边(失配指针),
<a id="markdown-54-treap" name="54-treap"></a>
## 5.4. treap
[前面提到](#21-随机构造的二叉查找树), 随机构造的二叉查找树高度为 $h=O(logn)$,以及在[算法 general](https://mbinary.coding.me/alg-genral.html) 中说明了怎样 随机化(shuffle)一个给定的序列.
[前面提到](#21-随机构造的二叉查找树), 随机构造的二叉查找树高度为 $h=O(logn)$,以及在[算法 general](https://mbinary.xyz/alg-genral.html) 中说明了怎样 随机化(shuffle)一个给定的序列.
所以,为了得到一个平衡的二叉排序树,我们可以将给定的序列随机化, 然后再进行构造二叉排序树.

View File

@ -3,7 +3,7 @@
# File : lcs.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-08-25 12:00
# Description:

View File

@ -3,7 +3,7 @@
# File : matrixChainMultiply.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-05 19:09
# Description:

View File

@ -3,7 +3,7 @@
# File : splitStripe.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-08-24 17:07
# Description:

View File

@ -4,7 +4,7 @@
# File : stoneGame.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-14 14:32
# Description:

View File

@ -4,7 +4,7 @@
# File : wildcard_matching.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-13 22:46
# Description:

View File

@ -4,7 +4,7 @@
# File : isBipartGraph.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-21 15:00
# Description: Judge if a graph is bipartite

View File

@ -1,5 +1,5 @@
# Number Theory
>See more details on [my blog](https://mbinary.coding.me/number-theory.html)
>See more details on [my blog](https://mbinary.xyz/number-theory.html)
## gcd.py
- gcd(a,b)

View File

@ -3,7 +3,7 @@
# File : num_weight.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 21:36
# Description:

View File

@ -4,7 +4,7 @@
# File : fastPow.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-17 21:39
# Description: fast power

View File

@ -4,7 +4,7 @@
# File : euler.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-16 10:53
# Description:

View File

@ -4,7 +4,7 @@
# File : factorize.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-16 09:36
# Description: factorization, using pollard's rho algorithm and miller-rabin primality test

View File

@ -4,7 +4,7 @@
# File : gcd.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-16 10:06
# Description:

View File

@ -4,7 +4,7 @@
# File : hammingDistance.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-17 17:36
# Description:

View File

@ -3,7 +3,7 @@
# File : isPrime.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-03-04 21:34
# Description:

View File

@ -3,7 +3,7 @@
# File : modulo_equation.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-3-4 21:14
# Description:

View File

@ -3,7 +3,7 @@
# File : interplotion.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02 21:14
# Description:
@ -14,7 +14,7 @@
# File : interplotion.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.github.io
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-18 09:29
# Description: 插值计算,有牛顿插值,拉格朗日插值,以及通过插值得到的多项式估计新的函数值

View File

@ -3,7 +3,7 @@
# File : iteration.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02 21:14
# Description:

View File

@ -3,7 +3,7 @@
# File : least_square.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02 21:14
# Description:
@ -15,7 +15,7 @@
> Author: mbinary
> Mail: zhuheqin1@gmail.com
> Created Time: Sat 07 Apr 2018 09:55:25 PM DST
> Blog: https://mbinary.github.io
> Blog: https://mbinary.xyz
> Description: 最小二乘法解线性方程组, 解矛盾方程组
************************************************************************'''

View File

@ -3,7 +3,7 @@
# File : linear_equation.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02 21:14
# Description:
@ -15,7 +15,7 @@
> File Name: doolittle.py
> Author: mbinary
> Mail: zhuheqin1@gmail.com
> Blog: https://mbinary.github.io
> Blog: https://mbinary.xyz
> Created Time: 2018-04-20 08:32
************************************************************************'''

View File

@ -3,7 +3,7 @@
# File : numerical_differential.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02 21:14
# Description:

View File

@ -3,7 +3,7 @@
# File : numerical_integration.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02 21:14
# Description:
@ -15,7 +15,7 @@
# File : numerical integration.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.github.io
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-11 08:58
# Description:

View File

@ -3,7 +3,7 @@
# File : solve-linear-by-iteration.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02 21:14
# Description:
@ -15,7 +15,7 @@
# File : solve-linear-by-iteration.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.github.io
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-04 07:42
# Description:

View File

@ -3,7 +3,7 @@
# File : vector_norm.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02 21:14
# Description:

View File

@ -3,7 +3,7 @@
# File : permute_back_track.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-25 12:32
# Description:

View File

@ -3,7 +3,7 @@
# File : permute_cantor.c
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-17 11:25
# Description:

View File

@ -3,7 +3,7 @@
# File : permute_divide_and_conquer.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-25 12:23
# Description:

View File

@ -3,7 +3,7 @@
# File : permute_next_permutation.c
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-17 14:31
# Description: support duplicate values.

View File

@ -3,7 +3,7 @@
# File : 8Astar.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 23:06
# Description:

View File

@ -3,7 +3,7 @@
# File : BFS_knight.hs
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-11 19:40
# Description:

View File

@ -3,7 +3,7 @@
# File : bloomFilter.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-17 11:19
# Description:

View File

@ -3,7 +3,7 @@
# File : schedule.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-30 12:00
# Description:

37
search/work_dispatch.py Normal file
View File

@ -0,0 +1,37 @@
'''
设有n件工作要分配给n个人去完成将工作i分配给第j个人所需费用为c_ij 试设计一个算法为每个人分配1件不同的工作并使总费用达到最小
'''
def dispatch(mat):
'''mat: matrix of c_ij'''
def _util(i,arrange,cost):
''' for i-th work'''
nonlocal total,used,rst
if i==n:
total=cost
rst = arrange.copy() # copy is needed
else:
for j in range(n):
if not used[j] and( total is None or cost+mat[i][j]<total):
used[j]=True
arrange[i] = j
_util(i+1,arrange,cost+mat[i][j])
used[j]=False
total = None
rst = None
n = len(mat)
used = [False for i in range(n)]
_util(0,[-1]*n,0)
return total,rst
import random
if __name__=='__main__':
n = 10
mat = [[random.randint(1,100) for i in range(n)] for i in range(n)]
print('work matrix: c_ij: work_i and person_j')
for i in range(n):
print(mat[i])
print('result: ',end='')
print(dispatch(mat))

View File

@ -3,7 +3,7 @@
# File : sort.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-05 17:18
# Description:

View File

@ -3,7 +3,7 @@
# File : heapSort.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-05 16:24
# Description:

View File

@ -3,7 +3,7 @@
# File : quickSort.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-06 10:31
# Description:

View File

@ -3,7 +3,7 @@
# File : radixSort.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-06 15:52
# Description:

View File

@ -3,7 +3,7 @@
# File : select.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-06 17:13
# Description:

View File

@ -3,7 +3,7 @@
# File : shellSort.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-06 16:30
# Description:

View File

@ -4,7 +4,7 @@
# File : KMP.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-11 14:02
# Description:

View File

@ -3,7 +3,7 @@
# File : manacher.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-06 15:56
# Description:

View File

@ -3,7 +3,7 @@
# File : markov.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-06 15:57
# Description:

View File

@ -4,7 +4,7 @@
# File : rabin_karp.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-11 00:01
# Description: rabin-karp algorithm

112
string/rotate.py Normal file
View File

@ -0,0 +1,112 @@
''' mbinary
#########################################################################
# File : rotate.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19 21:54
# Description: three methods of rotating a list
1. 利用 ba=(br)^T(ar)^T=(arbr)^T通过三次反转字符串: 即首先对序列前部分逆序再对序列后部分逆序再对整个序列全部逆序
2. 分组交换(尽可能使数组的前面连续几个数为所要结果):a长度大于b ab 分成 a0a1b交换 a0 b ba1a0只需再交换 a1和 a0 a 长度小于 b ab 分成 ab0b1交换 a b0 b0ab1只需再交换 a 和b0通过不断将数组划分和交换直到不能再划分为止分组过程与求最大公约数很相似
3.所有序号为 (j+i*m) % n (j 表示每个循环链起始位置i 为计数变量m 表示左旋转位数n 表示字符串长度)会构成一个循环链共有 gcd(n,m)gcd nm 的最大公约数每个循环链上的元素只要移动一个位置即可最后整个过程总共交换了 n 每一次循环链是交换 n/gcd(n,m)总共 gcd(n,m)个循环链所以总共交换 n
#########################################################################
'''
def rotate(s,k,right=False):
def reverse(a,b):
while a<b:
s[a],s[b]=s[b],s[a]
a+=1
b-=1
n=len(s)
k = k%n if not right else n-k%n
reverse(0,k-1)
reverse(k,n-1)
reverse(0,n-1)
return s
def rotate2(s,k,right=False):
def swap(a,b,c):
for i in range(c):
s[a+i],s[b+i] = s[b+i],s[a+i]
def _rot(pl,pr):
''' swap s[pl,pr) , s[pr:]'''
if pr==n:return
if pr-pl<=n-pr:
swap(pl,pr,pr-pl)
_rot(pr,2*pr-pl)
else:
swap(pl,pr,n-pr)
_rot(n-pr+pl,pr)
n=len(s)
k = k%n if not right else n-k%n
_rot(0,k)
return s
def rotate3(s,k,right=False):
def gcd(a,b):
if b==0:return a
return gcd(b,a%b)
n=len(s)
k = k%n if not right else n-k%n
r=gcd(n,k)
for i in range(r):
tmp = s[i]
j = (i+k)%n
while j!=i:
s[j-k] = s[j]
j = (j+k)%n
s[(j-k+n)%n] = tmp
return s
def test():
def f(func,*args,right=False):
print(' '.join(['testing:',func.__name__,str(args),'right=',str(right)]))
rst = func(*args,right=right)
print('result',rst)
print()
return f
if __name__=='__main__':
s=[i for i in range(10)]
tester= test()
tester(rotate,s,4,right=True)
tester(rotate,s,4)
tester(rotate2,s,2,right=True)
tester(rotate2,s,2)
tester(rotate3,s,132,right=True)
tester(rotate3,s,132)
'''
testing: rotate ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4) right= True
result [6, 7, 8, 9, 0, 1, 2, 3, 4, 5]
testing: rotate ([6, 7, 8, 9, 0, 1, 2, 3, 4, 5], 4) right= False
result [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
testing: rotate2 ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 2) right= True
result [8, 9, 0, 1, 2, 3, 4, 5, 6, 7]
testing: rotate2 ([8, 9, 0, 1, 2, 3, 4, 5, 6, 7], 2) right= False
result [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
testing: rotate3 ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 132) right= True
result [8, 9, 0, 1, 2, 3, 4, 5, 6, 7]
testing: rotate3 ([8, 9, 0, 1, 2, 3, 4, 5, 6, 7], 132) right= False
result [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
'''

View File

@ -3,7 +3,7 @@
# File : sunday.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-11 15:26
# Description: 字符串模式匹配, sunday 算法, kmp 的改进

View File

@ -4,7 +4,7 @@
# File : wildcard_matching.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-13 22:46
# Description:

View File

@ -1,5 +1,13 @@
README = r'''
# Algorithm
# Algorithm and data structures
[![Stars](https://img.shields.io/github/stars/mbinary/algorithm-in-python.svg?label=Stars&style=social)](https://github.com/mbinary/algorithm-in-python/stargazers)
[![Forks](https://img.shields.io/github/forks/mbinary/algorithm-in-python.svg?label=Fork&style=social)](https://github.com/mbinary/algorithm-in-python/network/members)
[![repo-size](https://img.shields.io/github/repo-size/mbinary/algorithm-in-python.svg)]()
[![License](https://img.shields.io/badge/LICENSE-WTFPL-blue.svg)](LICENSE)
[![Language](https://img.shields.io/badge/language-python3-orange.svg)]()
<!-- [![Build](https://travis-ci.org/mbinary/PL0-compiler.svg?branch=master)]() -->
>Notes and codes for learning algorithm and data structures :smiley:
Some pictures and ideas are from `<<Introduction to Algotithm>>`
@ -7,7 +15,7 @@ Some pictures and ideas are from `<<Introduction to Algotithm>>`
I use python 3.6+ and c/c++ to implement them.
# Notice
Currently, Github can't render latex math formulas.Thus,if you want to view the markodwn notes which contain latex math formulas, you can visit [my blog](https://mbinary.coding.me)
Currently, Github can't render latex math formulas.Thus,if you want to view the markodwn notes which contain latex math formulas, you can visit [my blog](https://mbinary.xyz)
# Index
{index}
@ -18,7 +26,7 @@ HEAD = '''{begin} mbinary
# File : {name}
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: {ctime}
# Description:

View File

@ -3,7 +3,7 @@
# File : genReadme.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-11 15:53
# Description:
@ -17,7 +17,7 @@ from config import README
parser = ArgumentParser()
parser.add_argument('-p','--path',default='.',help='path to walk')
parser.add_argument('-f','--fileinclude',action='store_true',help='if has, list files and dirs, else only dirs')
parser.add_argument('-f','--fileinclude',action='store_true',default=True,help='if has, list files and dirs, else only dirs')
parser.add_argument('-d','--depth', type = int, default = 2)
#获取参数
args = parser.parse_args()

View File

@ -3,7 +3,7 @@
# File : headInfo.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-07-08 14:48
# Description:

View File

@ -3,7 +3,7 @@
# File : tree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-12-11 15:56
# Description: