精心整理2万字c++知识点
制作不易,求一鍵三連~
文章目錄
- 1、基本數據結構
- 數組
- 鏈表
- 隊列、單調隊列、雙端隊列
- 棧
- 2、中極數據結構
- 堆
- 并查集與帶權并查集
- hash表
- 自然溢出
- 雙hash
- 3、高級數據結構
- 樹狀數組
- 線段樹及其合并
- Zkw線段樹
- Fhq線樹
- 超哥線段樹
- 平衡樹
- Treap隨機平衡二叉樹
- Splay伸展樹
- Scapegoat Tree替罪羊樹
- 后綴平衡樹
- 塊狀數組、塊狀鏈表
- 樹套樹
- 線段樹套線段樹
- 線段樹套平衡樹
- 平衡樹套線段樹
- 可并堆
- 左偏樹
- 配對堆
- KDTree、四分樹
- 舞蹈鏈(DLX)、二進制分組
- 劃分樹
- 4、可持久化數據結構
- 可持久化線段樹(主席樹)
- 可持久化平衡樹
- 可持久化塊狀數組
- 5、字符串相關算法及數據結構
- KMP
- AC自動機
- 后綴數組
- 后綴樹
- 后綴自動機
- 字典樹Trie
- Manacher
- 6、圖論相關
- 最小生成樹
- Prim
- Kruskal
- 最短路、次短路、K短路
- Spfa
- Dijkstra
- Floyd
- 圖的聯通
- 連通分量
- 割點、割邊
- 網絡流
- 最大流
- 最小割
- 費用流
- 分數規劃
- 樹相關
- 樹上倍增、公共祖先
- 樹鏈剖分
- 樹的分治算法(點分治、邊分治、動態樹分治)
- 動態樹(LCT、樹分塊)
- 虛樹
- prufer編碼
- 拓撲排序
- 歐拉圖
- 二分圖
- KM算法
- 匈牙利算法
- 仙人掌算法
- 7、數學相關
- (擴展)歐幾里得算法、篩法、快速冪
- 斐蜀定理
- 更相減損術
- 歐拉函數與降冪
- 費馬小定理
- 排列組合
- Lucas定理
- 楊輝三角
- 乘法逆元
- 矩陣乘法
- 數學期望與概率
- 博弈論
- Sg函數
- 樹上刪邊游戲
- 拉格朗日乘子法
- 中國剩余定理
- 線性規劃與網絡流
- 辛普森積分
- 模擬線性方程組
- 容斥原理與莫比烏斯反演
- 快速傅立葉變換
- 大步小步BSGS法(擴展)
- 高斯消元
- 線性篩
- Min25篩與杜教篩
- 母函數
- Burnside引理與Polya計數
- Miller-Robin素數檢測
- Pollard大數分解
- 8、動態規劃
- 基礎形式(記憶化搜索、斯坦納樹、背包九講)
- 背包dp
- 線性dp
- 區間dp
- 狀壓dp
- 環形dp
- 樹形dp
- 數位dp
- 倍增dp
- 插頭dp
- 斜率優化與四邊形不等式優化
- 環+外向樹上的dp
- 9、計算幾何
- 計算幾何基礎
- 三位計算幾何初步
- 梯形剖分與三角形剖分
- 凸包
- 旋轉卡殼
- 半平面交
- pick定理
- 掃描線
- 10、搜索相關
- dfs、bfs
- A*算法
- 迭代加深搜索(IDA*)、雙向廣搜
- 11、特殊算法
- 莫隊算法、樹上莫隊
- 模擬退火
- 爬山算法
- 隨機增量算法
- 12、其他重要工具與方法
- 模擬與貪心
- 二分法、三分法(求偏導)
- 分治、CDQ分治
- 高精度
- 離線
- ST表
- 13、STL
- map
- priority_queue
- set
- bitset
- rope
- 14、非常見算法
- 朱劉算法
- 弦圖與區間圖
1、基本數據結構
數組
數組(Array)是有序的元素序列。 [1] 若將有限個類型相同的變量的集合命名,那么這個名稱為數組名。組成數組的各個變量稱為數組的分量,也稱為數組的元素,有時也稱為下標變量。用于區分數組的各個元素的數字編號稱為下標。數組是在程序設計中,為了處理方便, 把具有相同類型的若干元素按有序的形式組織起來的一種形式。 [1] 這些有序排列的同類數據元素的集合稱為數組。
數組是用于儲存多個相同類型數據的集合。
鏈表
鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點(鏈表中每一個元素稱為結點)組成,結點可以在運行時動態生成。每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。 相比于線性表順序結構,操作復雜。由于不必須按順序存儲,鏈表在插入的時候可以達到O(1)的復雜度,比另一種線性表順序表快得多,但是查找一個節點或者訪問特定編號的節點則需要O(n)的時間,而線性表和順序表相應的時間復雜度分別是O(logn)和O(1)。
使用鏈表結構可以克服數組鏈表需要預先知道數據大小的缺點,鏈表結構可以充分利用計算機內存空間,實現靈活的內存動態管理。但是鏈表失去了數組隨機讀取的優點,同時鏈表由于增加了結點的指針域,空間開銷比較大。鏈表最明顯的好處就是,常規數組排列關聯項目的方式可能不同于這些數據項目在記憶體或磁盤上順序,數據的存取往往要在不同的排列順序中轉換。鏈表允許插入和移除表上任意位置上的節點,但是不允許隨機存取。鏈表有很多種不同的類型:單向鏈表,雙向鏈表以及循環鏈表。鏈表可以在多種編程語言中實現。像Lisp和Scheme這樣的語言的內建數據類型中就包含了鏈表的存取和操作。程序語言或面向對象語言,如C,C++和Java依靠易變工具來生成鏈表。
隊列、單調隊列、雙端隊列
隊列是一種特殊的線性表,特殊之處在于它只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。
單調隊列,即單調遞減或單調遞增的隊列。使用頻率不高,但在有些程序中會有非同尋常的作用。
deque(double-ended queue,雙端隊列)是一種具有隊列和棧的性質的數據結構。雙端隊列中的元素可以從兩端彈出,相比list增加[]運算符重載。
棧
棧(stack)又名堆棧,它是一種運算受限的線性表。限定僅在表尾進行插入和刪除操作的線性表。這一端被稱為棧頂,相對地,把另一端稱為棧底。向一個棧插入新元素又稱作進棧、入棧或壓棧,它是把新元素放到棧頂元素的上面,使之成為新的棧頂元素;從一個棧刪除元素又稱作出棧或退棧,它是把棧頂元素刪除掉,使其相鄰的元素成為新的棧頂元素。
2、中極數據結構
堆
堆(Heap)是計算機科學中一類特殊的數據結構的統稱。堆通常是一個可以被看做一棵完全二叉樹的數組對象。
并查集與帶權并查集
并查集,在一些有N個元素的集合應用問題中,我們通常是在開始時讓每個元素構成一個單元素的集合,然后按一定順序將屬于同一組的元素所在的集合合并,其間要反復查找一個元素在哪個集合中。這一類問題近幾年來反復出現在信息學的國際國內賽題中。其特點是看似并不復雜,但數據量極大,若用正常的數據結構來描述的話,往往在空間上過大,計算機無法承受;即使在空間上勉強通過,運行的時間復雜度也極高,根本就不可能在比賽規定的運行時間(1~3秒)內計算出試題需要的結果,只能用并查集來描述。
并查集是一種樹型的數據結構,用于處理一些不相交集合(disjoint sets)的合并及查詢問題。常常在使用中以森林來表示。
帶權并查集是普通并查集的進階版本,功能更加強大。
普通并查集只能判斷兩個元素是否在一個集合中,帶權并查集可以維護集合元素之間的關系,這個關系由每個元素的權值維護。
對權值的維護,我們需要在find(),unite()操作中分別進行修改。
hash表
散列表(Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。
給定表M,存在函數f(key),對任意給定的關鍵字值key,代入函數后若能得到包含該關鍵字的記錄在表中的地址,則稱表M為哈希(Hash)表,函數f(key)為哈希(Hash) 函數。
自然溢出
溢出哈希表是在hash 表填入過程中,將沖突的元素順序填入到溢出表中,而當查找過程中發現沖突時,就在溢出表中進行順序查找。
雙hash
雙重哈希屬于開放地址哈希中的一種解決沖突方案,也就是說如果一次哈希不能解決問題的時候,要再次哈希
3、高級數據結構
樹狀數組
樹狀數組或二叉索引樹(英語:Binary Indexed Tree),又以其發明者命名為Fenwick樹,最早由Peter M. Fenwick于1994年以A New Data Structure for Cumulative Frequency Tables為題發表在SOFTWARE PRACTICE AND EXPERIENCE。其初衷是解決數據壓縮里的累積頻率(Cumulative Frequency)的計算問題,現多用于高效計算數列的前綴和, 區間和。
線段樹及其合并
線段樹合并說全來就是動態開點權值線段樹合并,所以你需要掌握權值線段樹的基本知識以及知道什么是動態開點
對于兩個普通權值線段樹如果暴力合并的話復雜度將會是n log ?n,更別說是合并n棵權值線段樹了(炸空間、炸內存),但是在動態開點權值線段樹中,這一操作是可以優化為log n的。
Zkw線段樹
遞歸式線段樹的常數很大,經常被卡,而zkw線段樹的常數很小
Fhq線樹
FHQ Treap,又名無旋Treap,是一種不需要旋轉的平衡樹,是范浩強基于Treap發明的。FHQ Treap具有代碼短,易理解,速度快的優點。(當然跟紅黑樹等更高級的平衡樹比一下就是……)至少它在OI中算是很優秀的數據結構了。
超哥線段樹
超哥線段樹,實際上是線段樹的標記永久化。
平衡樹
平衡樹(Balance Tree,BT) 指的是,任意節點的子樹的高度差都小于等于1。常見的符合平衡樹的有,B樹(多路平衡搜索樹)、AVL樹(二叉平衡搜索樹)等。平衡樹可以完成集合的一系列操作, 時間復雜度和空間復雜度相對于“2-3樹”要低,在完成集合的一系列操作中始終保持平衡,為大型數據庫的組織、索引提供了一條新的途徑。 [1]
設“2-3 樹”的每個結點存放一組與應用問題有關的數據, 且有一個關鍵字 (>0的整數) 作為標識。關鍵字的存放規則如下:對于結點X, 設左、中、右子樹均不空, 則左子樹任一結點的關鍵字小于中子樹中任一結點的關鍵字;中子樹中任一結點的關鍵字小于結點X的關鍵字;而X的關鍵字又小于右子樹中任一結點的關鍵字, 稱這樣的“2-3樹”為平衡樹。[1]
Treap隨機平衡二叉樹
樹堆(Treap)是二叉排序樹(Binary Sort Tree)與堆(Heap)結合產生的一種擁有堆性質的二叉排序樹。
Splay伸展樹
Splay(伸展樹)是一種二叉排序樹,它能在O(log2 n)的時間內完成插入、查找和刪除操作。
Splay(伸展樹)能實現線段樹不能實現的操作,比如區間翻轉。
Splay的核心函數是旋轉操作,將點x旋轉至點k下面。特別的rotate (x, 0)表示把x旋轉至根。旋轉操作不會改變每個節點在該樹的中序遍歷中的位置。
旋轉的目的:在每次查詢、修改操作完,將操作的節點旋轉到根,就像是輸入法,常用的詞匯會在第一頁就出現,如果是第一次用,則需要翻好幾頁。可以保證均攤的時間復雜度為 [公式] 。
Scapegoat Tree替罪羊樹
替罪羊樹是計算機科學中,一種基于部分重建的自平衡二叉搜索樹。在替罪羊樹上,插入或刪除節點的平攤最壞時間復雜度是O(log n),搜索節點的最壞時間復雜度是O(log n)
后綴平衡樹
如果需要動態維護后綴數組,支持在字符串前端插入一個字符,詢問后綴的大小關系,如何做呢?
這是一個不斷插入的問題,可以從增量的角度考慮。我們在前端插入一個字符,其實就是插入了一個新的后綴。我們的問題其實就是這個后綴排名多少。我們可以用平衡樹維護一下后綴數組,從根節點開始二分比較這個后綴的大小,看看它應該被插到哪里。現在問題就變成了快速比較一個新的后綴和一個已有的后綴。
如果這個新的后綴和當前比較的后綴的首字符不同,那么比較結果是顯然的;如果新的后綴和當前比較的后綴的首字符相同,那么問題就轉化成了比較原來已有的兩個后綴的大小關系。我們在平衡樹的每個節點上維護一個值x∈[0,1],代表它的大小,左兒子為的關鍵值為[l,mid],右兒子的關鍵值為[mid,r],那么只要直接比較這個值就可以啦。
然而如果平衡樹的深度過大,那么這個值會爆實數的精度。所以我們采用深度為O(logn)的平衡樹。但如果平衡樹需要旋轉,那么它的子樹需要全部重新計算關鍵值。所以我們需要使用重量平衡樹,其子樹大小均攤O(logn),所以每次插入旋轉后整個子樹重算一下。
塊狀數組、塊狀鏈表
塊狀數組,即把一個數組分為幾個塊,塊內信息整體保存,若查詢時遇到兩邊不完整的塊直接暴力查詢。一般情況下,塊的長度為O(√n) 。
樹套樹
線段樹套線段樹
樹套樹寫法還是比較好理解的,不過要是讓自己硬套的話可能很不容易套出來的
這里的二維線段樹,外層線段樹是對方陣的正投影,而內層線段樹是對方陣的側投影
線段樹套平衡樹
線段樹的作用是區間修改和查詢,平衡樹的作用是查詢第k大,k的排名,前驅,后繼。這兩個結合起來,就變成了可以區間修改和查詢第k大,k的排名,前驅,后繼的數據結構:樹套樹-線段樹套平衡樹。
平衡樹套線段樹
線段樹維護的是區間,然后對于線段樹維護的區間的所有數字都維護一個平衡樹,然后所有的操作都對每個平衡樹單獨處理。
可并堆
可并堆,顧名思義,就是可以合并的堆。堆滿足一個性質,就是當前節點,都大于或者等于他的所有子樹上的節點,自然在這里我所講的是結點的權值。顯而易見,既然可并堆是堆的一種,容易推出,可并堆也滿足這個性質。
左偏樹
左偏樹(英語:leftist tree或leftist heap),也可稱為左偏堆、左傾堆,是計算機科學中的一種樹,是一種優先隊列實現方式,屬于可并堆,在信息學中十分常見,在統計問題、最值問題、模擬問題和貪心問題等等類型的題目中,左偏樹都有著廣泛的應用。斜堆是比左偏樹更為一般的數據結構。
配對堆
配對堆是一種實現簡單、均攤復雜度優越的堆數據結構,由Michael Fredman、羅伯特·塞奇威克、Daniel Sleator、羅伯特·塔揚于1986年發明。配對堆是一種多叉樹,并且可以被認為是一種簡化的斐波那契堆。對于實現例如普林姆最小生成樹算法等算法,配對堆是一個更優的選擇,
KDTree、四分樹
kd-tree(k-dimensional樹的簡稱),是一種對k維空間中的實例點進行存儲以便對其進行快速檢索的樹形數據結構。 [1] 主要應用于多維空間關鍵數據的搜索(如:范圍搜索和最近鄰搜索)。K-D樹是二進制空間分割樹的特殊的情況。
在計算機科學里,k-d樹( k-維樹的縮寫)是在k維歐幾里德空間組織點的數據結構。k-d樹可以使用在多種應用場合,如多維鍵值搜索(例:范圍搜尋及最鄰近搜索)。k-d樹是空間二分樹(Binary space partitioning )的一種特殊情況。 [2]
四分樹就是用一個類似于線段樹的東西來維護一個矩陣,就是每個點有四個兒子
然后每個兒子代表切分之后的一塊區域
舞蹈鏈(DLX)、二進制分組
舞蹈鏈(Dancing Links)算法在求解精確覆蓋問題時效率驚人。
二進制分組就是把操作的數量二進制拆分,每個二進制位數用數據結構維護
合并的時候,暴力重構
每次查詢,從logn個塊依次用維護的數據結構查詢
劃分樹
劃分樹定義為,它的每一個節點保存區間[lft,rht]所有元素,元素順序與原數組(輸入)相同,但是,兩個子樹的元素為該節點所有元素排序后(rht-lft+1)/2個進入左子樹,其余的到右子樹,同時維護一個num域,num[i]表示lft->i這個點有多少個進入了左子樹。
4、可持久化數據結構
可持久化線段樹(主席樹)
主席樹,也叫做可持久化線段樹,準確來說,應該叫做可持久化權值線段樹,因為其中的每一顆樹都是一顆權值線段樹。
所謂權值線段樹,就是指線段樹的葉子節點保存的是當前值的個數。這樣說起來比較抽象,下面用具體例子來簡單闡述。
可持久化平衡樹
treap = tree + heap,即同時滿足二叉搜索樹和堆的性質。
為了使樹盡可能的保證兩邊的大小平衡,所以有一個key值,使他滿足堆得性質,來維護樹的平衡,key值是隨機的。
treap有一般平衡樹的功能,前驅、后繼、第k大、查詢排名、插入、刪除。也比較好寫
可持久化塊狀數組
題目中要求可以查詢歷史狀態,最暴力的想法是開a[m][n]的二維數組,每次修改暴力復制并修改,每次查詢暴力掃描,時間復雜度是O(mn)的,但這顯然是不行的.
這個時候其實很容易想到線段樹,但線段樹維護的是當前狀態而無法維護歷史狀態,一種暴力的想法是開m棵線段樹,但這樣MLE的風險可謂巨大。
但我們發現,因為題目修改的是一個點的值,在線段樹上,會被修改的點只有logn個,因此可以每次只新建這logn個結點
5、字符串相關算法及數據結構
KMP
KMP算法是一種改進的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人們稱它為克努特—莫里斯—普拉特操作(簡稱KMP算法)。KMP算法的核心是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是通過一個next()函數實現,函數本身包含了模式串的局部匹配信息。KMP算法的時間復雜度O(m+n) [1] 。
AC自動機
Aho-Corasick automaton,該算法在1975年產生于貝爾實驗室,是著名的多模匹配算法。
要學會AC自動機,我們必須知道什么是Trie,也就是字典樹。Trie樹,又稱單詞查找樹或鍵樹,是一種樹形結構,是一種哈希樹的變種。典型應用是用于統計和排序大量的字符串(但不僅限于字符串),所以經常被搜索引擎系統用于文本詞頻統計。
后綴數組
在計算機科學里, 后綴數組(英語:suffix array)是一個通過對字符串的所有后綴經過排序后得到的數組。此數據結構被運用于全文索引、數據壓縮算法、以及生物信息學。
后綴數組被烏迪·曼伯爾與尤金·邁爾斯于1990年提出,作為對后綴樹的一種替代,更簡單以及節省空間。它們也被Gaston Gonnet 于1987年獨立發現,并命名為“PAT數組”。
后綴樹
后綴樹(Suffix tree)是一種數據結構,能快速解決很多關于字符串的問題。后綴樹的概念最早由Weiner于1973年提出,既而由McCreight在1976年和Ukkonen在1992年和1995年加以改進完善。
一個string S的后綴樹是一個邊(edge)被標記為字符串的樹。因此每一個S的后綴都唯一對應一條從根節點到葉節點的路徑。這樣就形成了一個S的后綴的基數樹(radix tree)。后綴樹是前綴樹(trie)里的一個特殊類型。
后綴自動機
首先,后綴自動機是一種有限狀態自動機,他可以識別且僅識別一個字符串的后綴。但是這不并不是后綴自動機強大的地方,我可以說如果把AC自動機反向插入我同樣可以做到這一點。
后綴自動機真正的用處在于:它可以識別一個串的所有子串。
非常優秀的是后綴自動機只會有O(n)個節點,也就是說在字符集看做常數的情況下,對于后綴自動機的構建可以做到O(n)。
后綴自動機不同于AC自動機的地方在于:它并不是一棵樹,不看prarent鏈的話,后綴自動機是一張DAG,這就讓后綴自動機每一個節點的意義玄妙了起來。
字典樹Trie
又稱單詞查找樹,Trie樹,是一種樹形結構,是一種哈希樹的變種。典型應用是用于統計,排序和保存大量的字符串(但不僅限于字符串),所以經常被搜索引擎系統用于文本詞頻統計。它的優點是:利用字符串的公共前綴來減少查詢時間,最大限度地減少無謂的字符串比較,查詢效率比哈希樹高。
Manacher
馬拉車算法 Manacher‘s Algorithm 是用來查找一個字符串的最長回文子串的線性方法,由一個叫Manacher的人在1975年發明的,這個方法的最大貢獻是在于將時間復雜度提升到了線性。
6、圖論相關
最小生成樹
一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,并且有保持圖連通的最少的邊。 [1] 最小生成樹可以用kruskal(克魯斯卡爾)算法或prim(普里姆)算法求出。
Prim
普里姆算法(Prim算法),圖論中的一種算法,可在加權連通圖里搜索最小生成樹。意即由此算法搜索到的邊子集所構成的樹中,不但包括了連通圖里的所有頂點(英語:Vertex (graph theory)),且其所有邊的權值之和亦為最小。該算法于1930年由捷克數學家沃伊捷赫·亞爾尼克(英語:Vojtěch Jarník)發現;并在1957年由美國計算機科學家羅伯特·普里姆(英語:Robert C. Prim)獨立發現;1959年,艾茲格·迪科斯徹再次發現了該算法。因此,在某些場合,普里姆算法又被稱為DJP算法、亞爾尼克算法或普里姆-亞爾尼克算法。
Kruskal
克魯斯卡爾算法是求連通網的最小生成樹的另一種方法。與普里姆算法不同,它的時間復雜度為O(eloge)(e為網中的邊數),所以,適合于求邊稀疏的網的最小生成樹 [1] 。
最短路、次短路、K短路
Spfa
SPFA 算法是 Bellman-Ford算法 的隊列優化算法的別稱,通常用于求含負權邊的單源最短路徑,以及判負權環。SPFA 最壞情況下復雜度和樸素 Bellman-Ford 相同,為 O(VE)。
Dijkstra
迪杰斯特拉算法(Dijkstra)是由荷蘭計算機科學家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是從一個頂點到其余各頂點的最短路徑算法,解決的是有權圖中最短路徑問題。迪杰斯特拉算法主要特點是從起始點開始,采用貪心算法的策略,每次遍歷到始點距離最近且未訪問過的頂點的鄰接節點,直到擴展到終點為止。 [1]
Floyd
Floyd算法又稱為插點法,是一種利用動態規劃的思想尋找給定的加權圖中多源點之間最短路徑的算法,與Dijkstra算法類似。該算法名稱以創始人之一、1978年圖靈獎獲得者、斯坦福大學計算機科學系教授羅伯特·弗洛伊德命名。 [1]
圖的聯通
連通分量
無向圖G的極大連通子圖稱為G的連通分量( Connected Component)。任何連通圖的連通分量只有一個,即是其自身,非連通的無向圖有多個連通分量。
割點、割邊
在一個無向圖中,如果有一個頂點集合,刪除這個頂點集合以及這個集合中所有頂點相關聯的邊以后,圖的連通分量增多,就稱這個點集為割點集合。
如果某個割點集合只含有一個頂點X(也即{X}是一個割點集合),那么X稱為一個割點。
假設有連通圖G,e是其中一條邊,如果G-e是不連通的,則邊e是圖G的一條割邊。此情形下,G-e必包含兩個連通分支。
網絡流
網絡流(network-flows)是一種類比水流的解決問題方法,與線性規劃密切相關。網絡流的理論和應用在不斷發展,出現了具有增益的流、多終端流、多商品流以及網絡流的分解與合成等新課題。網絡流的應用已遍及通訊、運輸、電力、工程規劃、任務分派、設備更新以及計算機輔助設計等眾多領域。
最大流
管道網絡中每條邊的最大通過能力(容量)是有限的,實際流量不超過容量。
最大流問題(maximum flow problem),一種組合最優化問題,就是要討論如何充分利用裝置的能力,使得運輸的流量最大,以取得最好的效果。求最大流的標號算法最早由福特和福克遜于1956年提出,20世紀50年代福特(Ford)、福克遜(Fulkerson)建立的“網絡流理論”,是網絡應用的重要組成成分。
最小割
最小割,圖中所有的割中,邊權值和最小的割為最小割。
費用流
最小費用流問題是一種組合最優化問題,也是網絡流理論研究的一個重要問題。
分數規劃
樹相關
樹上倍增、公共祖先
LCA(least common ancestors)最近公共祖先
指的就是對于一棵有根樹,若結點z既是x的祖先,也是y的祖先,那么z就是結點x和y的最近公共祖先。
對于有根樹T的兩個結點u、v,最近公共祖先LCA(T,u,v)表示一個結點x,滿足x是u和v的祖先且x的深度盡可能大。在這里,一個節點也可以是它自己的祖先。
樹鏈剖分
樹鏈剖分,計算機術語,指一種對樹進行劃分的算法,它先通過輕重邊剖分將樹分為多條鏈,保證每個點屬于且只屬于一條鏈,然后再通過數據結構(樹狀數組、BST、SPLAY、線段樹等)來維護每一條鏈。
樹的分治算法(點分治、邊分治、動態樹分治)
點分治,顧名思義就是基于樹上的節點進行分治。
如果我們在深入一點呢?對于點的拆開其實就是對于樹的拆開。
所以我認為點分治的本質其實是將一棵樹拆分成許多棵子樹處理,并不斷進行。
這應該也是點分治的精髓。
邊分治的分治過程與點分治類似,同樣每次分治時找到一條分治中心邊使這條邊兩端的兩個聯通塊中較大的一個盡量小。以分治中心邊為界限,恰好將當前分治的聯通塊中的點分成了兩部分,統計路徑經過分治中心邊的答案,然后將分治中心邊斷開,遞歸分治中心邊兩端的兩個聯通塊。
動態樹分治,顧名思義,解決待修改的樹分治問題。原本的樹分治基于邊或者重心的分治可以解決大多數靜態樹鏈問題,但是待修改怎么辦?其實很簡單,因為樹結構是不變的,就是樹分治的基礎結構不變,對于修改和詢問,只需要在第一次樹分治的基礎上用一些數據結構維護一些信息即可。
動態樹(LCT、樹分塊)
動態樹問題 ,是一類要求維護一個有根樹森林,支持對樹的分割, 合并等操作的問題。由RobertE.Tarjan為首的科學家們提出解決算法Link-Cut Trees,簡稱LCT。
虛樹
虛樹,是對于一棵給定的節點數為 n 的樹 T,構造一棵新的樹 T’ 使得總結點數最小且包含指定的某幾個節點和他們的LCA。
prufer編碼
prufer是無根樹的一種編碼方式,一棵無根樹和一個prufer編碼唯一對應,也就是一棵樹有唯一的prufer編碼,而一個prufer編碼對應一棵唯一的樹。
拓撲排序
對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊<u,v>∈E(G),則u在線性序列中出現在v之前。通常,這樣的線性序列稱為滿足拓撲次序(Topological Order)的序列,簡稱拓撲序列。簡單的說,由某個集合上的一個偏序得到該集合上的一個全序,這個操作稱之為拓撲排序。 [1]
歐拉圖
歐拉圖是指通過圖(無向圖或有向圖)中所有邊且每邊僅通過一次通路,相應的回路稱為歐拉回路。具有歐拉回路的圖稱為歐拉圖(Euler Graph),具有歐拉通路而無歐拉回路的圖稱為半歐拉圖。對歐拉圖的一個現代擴展是蜘蛛圖,它向歐拉圖增加了可以連接的存在點。這給予歐拉圖析取特征。歐拉圖已經有了合取特征(就是說區定義了有著與起來的那些性質的對象在區中的存在)。所以蜘蛛圖允許使用歐拉圖建模邏輯或的條件。
二分圖
二分圖又稱作二部圖,是圖論中的一種特殊模型。 設G=(V,E)是一個無向圖,如果頂點V可分割為兩個互不相交的子集(A,B),并且圖中的每條邊(i,j)所關聯的兩個頂點i和j分別屬于這兩個不同的頂點集(i in A,j in B),則稱圖G為一個二分圖。
KM算法
KM算法用來求二分圖最大權完美匹配。
匈牙利算法
匈牙利算法是一種在多項式時間內求解任務分配問題的組合優化算法,并推動了后來的原始對偶方法。1955年,庫恩(W.W.Kuhn)利用匈牙利數學家康尼格(D.K?nig)的一個定理構造了這個解法,故稱為匈牙利法。 [2]
仙人掌算法
仙人掌圖:每條邊至多在一個環上的圖。
仙人掌圖中每個環相當于一個點雙連通分量,那么用Tarjan算法處理dfs樹。
7、數學相關
(擴展)歐幾里得算法、篩法、快速冪
擴展歐幾里得算法是歐幾里得算法(又叫輾轉相除法)的擴展。除了計算a、b兩個整數的最大公約數,此算法還能找到整數x、y(其中一個很可能是負數)。通常談到最大公因子時, 我們都會提到一個非常基本的事實: 給予二整數 a 與 b, 必存在有整數 x 與 y 使得ax + by = gcd(a,b)。有兩個數a,b,對它們進行輾轉相除法,可得它們的最大公約數——這是眾所周知的。然后,收集輾轉相除法中產生的式子,倒回去,可以得到ax+by=gcd(a,b)的整數解。
篩法(挨拉托色尼篩法)是一種用來求所有小于N的素數的方法。把從2(素數是指大于1的自然數)開始的某一范圍內的正整數從小到大按順序排列,逐步篩掉非素數留下素數。
顧名思義,快速冪就是快速算底數的n次冪。其時間復雜度為 O(log?N), 與樸素的O(N)相比效率有了極大的提高。
斐蜀定理
在數論中,裴蜀定理是一個關于最大公約數(或最大公約式)的定理,裴蜀定理得名于法國數學家艾蒂安·裴蜀。
裴蜀定理說明了對任何整數 a、b和它們的最大公約數 d ,關于未知數 x以及 y 的線性的丟番圖方程(稱為裴蜀等式)。
更相減損術
更相減損術是出自《九章算術》的一種求最大公約數的算法,它原本是為約分而設計的,但它適用于任何需要求最大公約數的場合。
歐拉函數與降冪
在數論,對正整數n,歐拉函數是小于n的正整數中與n互質的數的數目。
把一個多項式的各項按照某個字母的指數從大到小的順序排列,叫做這一字母的降冪。如ab+(-2ba)+a為a的降冪。
費馬小定理
費馬小定理 (Fermat’s little theorem) 是數論中的一個重要定理,在1636年提出。如果p是一個質數,而整數a不是p的倍數,則有a ^ (p - 1) ≡ 1 (mod p)。[1]
排列組合
Lucas定理
Lucas定理是用來求 c(n,m) mod p,p為素數的值。
楊輝三角
楊輝三角,是二項式系數在三角形中的一種幾何排列,中國南宋數學家楊輝1261年所著的《詳解九章算法》一書中出現。在歐洲,帕斯卡(1623----1662)在1654年發現這一規律,所以這個表又叫做帕斯卡三角形。帕斯卡的發現比楊輝要遲393年,比賈憲遲600年。 [1]
乘法逆元
乘法逆元,是指數學領域群G中任意一個元素a,都在G中有唯一的逆元a‘,具有性質a×a’=a’×a=e,其中e為該群的單位元。
矩陣乘法
矩陣相乘最重要的方法是一般矩陣乘積。它只有在第一個矩陣的列數(column)和第二個矩陣的行數(row)相同時才有意義 [1] 。一般單指矩陣乘積時,指的便是一般矩陣乘積。一個m×n的矩陣就是m×n個數排成m行n列的一個數陣。由于它把許多數據緊湊地集中到了一起,所以有時候可以簡便地表示一些復雜的模型,如電力系統網絡模型。 [2]
數學期望與概率
在概率論和統計學中,數學期望(mean)(或均值,亦簡稱期望)是試驗中每次可能結果的概率乘以其結果的總和,是最基本的數學特征之一。它反映隨機變量平均取值的大小。
需要注意的是,期望值并不一定等同于常識中的“期望”——“期望值”也許與每一個結果都不相等。期望值是該變量輸出值的平均數。期望值并不一定包含于變量的輸出值集合里。
大數定律表明,隨著重復次數接近無窮大,數值的算術平均值幾乎肯定地收斂于期望值。
博弈論
博弈論,又稱為對策論(Game Theory)、賽局理論等,既是現代數學的一個新分支,也是運籌學的一個重要學科。
博弈論主要研究公式化了的激勵結構間的相互作用,是研究具有斗爭或競爭性質現象的數學理論和方法。博弈論考慮游戲中的個體的預測行為和實際行為,并研究它們的優化策略。生物學家使用博弈理論來理解和預測進化論的某些結果。
博弈論已經成為經濟學的標準分析工具之一。在金融學、證券學、生物學、經濟學、國際關系、計算機科學、政治學、軍事戰略和其他很多學科都有廣泛的應用。
Sg函數
給定一個有向無環圖和一個起始頂點上的一枚棋子,兩名選手交替的將這枚棋子沿有向邊進行移動,無法移 動者判負。事實上,這個游戲可以認為是所有公平組合游戲的抽象模型。
樹上刪邊游戲
在某一棵樹上刪除一條邊,同時刪去所有在刪除后不再與根相連的部分
雙方輪流操作,無法再進行刪除者判定為失敗
一個游戲中有多棵樹,我們把ta們的根都放在地板上,方便之后的處理
在此,我們討論的將是公平游戲,即雙方都可以刪除任意的樹邊
我們稱這個游戲為:Green Hachenbush(樹上公平刪邊游戲)
之所以強調是公平博弈,是因為還有另一種刪邊游戲,是不公平的,參與者雙方一方只能刪除藍邊,一方只能刪除紅邊,而綠邊雙方都可以刪除
拉格朗日乘子法
在數學最優問題中,拉格朗日乘數法(以數學家約瑟夫·路易斯·拉格朗日命名)是一種尋找變量受一個或多個條件所限制的多元函數的極值的方法。這種方法將一個有n 個變量與k 個約束條件的最優化問題轉換為一個有n + k個變量的方程組的極值問題,其變量不受任何約束。這種方法引入了一種新的標量未知數,即拉格朗日乘數:約束方程的梯度(gradient)的線性組合里每個向量的系數。 [1] 此方法的證明牽涉到偏微分,全微分或鏈法,從而找到能讓設出的隱函數的微分為零的未知數的值。
中國剩余定理
孫子定理是中國古代求解一次同余式組(見同余)的方法。是數論中一個重要定理。又稱中國余數定理。一元線性同余方程組問題最早可見于中國南北朝時期(公元5世紀)的數學著作《孫子算經》卷下第二十六題,叫做“物不知數”問題,原文如下:
有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二。問物幾何?即,一個整數除以三余二,除以五余三,除以七余二,求這個整數。《孫子算經》中首次提到了同余方程組問題,以及以上具體問題的解法,因此在中文數學文獻中也會將中國剩余定理稱為孫子定理。
線性規劃與網絡流
線性規劃(Linear programming,簡稱LP),是運籌學中研究較早、發展較快、應用廣泛、方法較成熟的一個重要分支,它是輔助人們進行科學管理的一種數學方法。研究線性約束條件下線性目標函數的極值問題的數學理論和方法。英文縮寫LP。
線性規劃是運籌學的一個重要分支,廣泛應用于軍事作戰、經濟分析、經營管理和工程技術等方面。為合理地利用有限的人力、物力、財力等資源作出的最優決策,提供科學的依據。
辛普森積分
辛普森積分法是一種用拋物線近似函數曲線來求定積分數值解的方法。把積分區間等分成若干段,對被積函數在每一段上使用辛普森公式,根據其在每一段的兩端和中點處的值近似為拋物線,逐段積分后加起來,即得到原定積分的數值解。辛普森積分法比梯形法則更精確,二者都是牛頓-柯特斯公式(Newton-Cotes)的特例。
模擬線性方程組
這個問題的源自《孫子算經》,其中有這樣一道算術題:“今有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二,問物幾何?”按照今天的話來說:一個數除以3余2,除以5余3,除以7余2,求這個數.這樣的問題,也有人稱為“韓信點兵”.它形成了一類問題,也就是初等數論中解同余式.這類問題的有解條件和解的方法被稱為“中國剩余定理”,這是由中國人首先提出的。
容斥原理與莫比烏斯反演
在計數時,必須注意沒有重復,沒有遺漏。為了使重疊部分不被重復計算,人們研究出一種新的計數方法,這種方法的基本思想是:先不考慮重疊的情況,把包含于某內容中的所有對象的數目先計算出來,然后再把計數時重復計算的數目排斥出去,使得計算的結果既無遺漏又無重復,這種計數的方法稱為容斥原理。 [1]
莫比烏斯反演是數論數學中很重要的內容,可以用于解決很多組合數學的問題。
快速傅立葉變換
快速傅里葉變換 (fast Fourier transform), 即利用計算機計算離散傅里葉變換(DFT)的高效、快速計算方法的統稱,簡稱FFT。快速傅里葉變換是1965年由J.W.庫利和T.W.圖基提出的。采用這種算法能使計算機計算離散傅里葉變換所需要的乘法次數大為減少,特別是被變換的抽樣點數N越多,FFT算法計算量的節省就越顯著。
大步小步BSGS法(擴展)
計算(y^x ≡ z mod p) 中 (x) 的解。
高斯消元
數學上,高斯消元法(或譯:高斯消去法),是線性代數規劃中的一個算法,可用來為線性方程組求解。但其算法十分復雜,不常用于加減消元法,求出矩陣的秩,以及求出可逆方陣的逆矩陣。不過,如果有過百萬條等式時,這個算法會十分省時。一些極大的方程組通常會用迭代法以及花式消元來解決。當用于一個矩陣時,高斯消元法會產生出一個“行梯陣式”。高斯消元法可以用在電腦中來解決數千條等式及未知數。亦有一些方法特地用來解決一些有特別排列的系數的方程組。 [1]
線性篩
在剛接觸編程語言時,對于尋找素數,第一時間想到的便是二重循環暴力查找,其復雜度O(n),通過循環中只判斷到根號n可以優化一些,不過復雜度也達不到預期。在數論的學習中,我學到了埃氏篩法,O(nloglogn)的算法,而在一些數據范圍達到1e7這樣的題目中,也很難讓人滿意,于是我便學習了歐拉篩法,也即 O(n)的線性篩法。
Min25篩與杜教篩
考慮一個積性函數F(x),用來快速計算前綴和
∑i=1nF(i)
當然,這個積性函數要滿足F(x),x∈Prime可以用多項式表示
同時,F(xk),x∈Prime要能夠快速計算答案
杜教篩是用來求一類積性函數的前綴和
它通過各種轉化,最終利用數論分塊的思想來降低復雜度
假設我們現在要求S(n)=∑ni=1f(i),f(i)為積性函數,n?1012
直接求肯定是不好求的,不過現在假設有另一個積性函數g
我們來求它們狄利克雷卷積的前綴和
∑i=1n(g?f)=∑i=1n∑d∣ig(d)f(id)
=∑d=1ng(d)∑d|if(id)
=∑d=1ng(d)∑i=1ndf(i)
=∑d=1ng(d)S(nd)
然后就化不動了,不過我們發現我們化出了nd!
但是S(n)怎么求呢?
容斥一下
g(1)S(n)=∑d=1ng(d)S(nd)?∑d=2ng(d)S(nd)
前半部分是狄利克雷卷積的前綴和的形式
后半部分可以數論分塊。這樣看起來就好搞多了
現在我們的問題是,如何選擇g才能使得上面這個式子好算
這個就要因情況而定了
母函數
生成函數即母函數,是組合數學中尤其是計數方面的一個重要理論和工具。生成函數有普通型生成函數和指數型生成函數兩種,其中普通型用的比較多。形式上說,普通型生成函數用于解決多重集的組合問題,而指數型母函數用于解決多重集的排列問題。母函數還可以解決遞歸數列的通項問題(例如使用母函數解決斐波那契數列的通項公式)。
Burnside引理與Polya計數
伯恩賽德引理(Burnside’s lemma),也叫伯恩賽德計數定理(Burnside’s counting theorem),柯西-弗羅貝尼烏斯引理(Cauchy-Frobenius lemma)或軌道計數定理(orbit-counting theorem),是群論中一個結果,在考慮對稱的計數中經常很有用。該結論被冠以多個人的名字,其中包括威廉·伯恩賽德(William Burnside)、波利亞、柯西和弗羅貝尼烏斯。這個命題不屬于伯恩賽德自己,他只是在自己的書中《有限群論 On the Theory of Groups of Finite Order》引用了,而將其歸于弗羅貝尼烏斯 (1887)。
Burnside定理之所以能夠計數不等價著色數,與它能夠計算C(f)有關,而C中的原色不變是f保持的,通過考慮置換的循環結構計算可變得容易簡便。
Miller-Robin素數檢測
快速概率測素數的算法------MillerRobin(),適用于測試單個素數,出錯概率比計算機本身出錯的概率還要低
為(1/4)^(s),一般s取50就可以認為是準確測試出了。
算法是基于費馬小定理(format),二次探測定理 x*x % p == 1 ,若P為素數,則x的解只能是x = 1或者x = p - 1)加上迭代乘法判斷的Miller算法
Pollard大數分解
Pollard_rho算法的大致流程是 先判斷當前數是否是素數(Miller_rabin)了,如果是則直接返回。如果不是素數的話,試圖找到當前數的一個因子(可以不是質因子)。然后遞歸對該因子和約去這個因子的另一個因子進行分解。
8、動態規劃
基礎形式(記憶化搜索、斯坦納樹、背包九講)
背包dp
背包問題(Knapsack problem)是一種組合優化的NP完全問題。問題可以描述為:給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內,我們如何選擇,才能使得物品的總價格最高。問題的名稱來源于如何選擇最合適的物品放置于給定背包中。相似問題經常出現在商業、組合數學,計算復雜性理論、密碼學和應用數學等領域中。也可以將背包問題描述為決定性問題,即在總重量不超過W的前提下,總價值是否能達到V?它是在1978年由Merkle和Hellman提出的。
背包問題已經研究了一個多世紀,早期的作品可追溯到1897年 [1] 數學家托比亞斯·丹齊格(Tobias Dantzig,1884-1956)的早期作品 [2] ,并指的是包裝你最有價值或有用的物品而不會超載你的行李的常見問題。
線性dp
線性DP是動態規劃問題中的一類問題,指狀態之間有線性關系的動態規劃問題。
區間dp
區間dp就是在一段區間上進行動態規劃。對于每段區間,他們的最優值都是由幾段更小區間的最優值得到,是分治思想的一種應用,將一個區間問題不斷劃分為更小的區間直至一個元素組成的區間,枚舉他們的組合 ,求合并后的最優值。
狀壓dp
狀態壓縮動態規劃,就是我們俗稱的狀壓DP,是利用計算機二進制的性質來描述狀態的一種DP方式。
環形dp
其實環形動態規劃也是區間型,只不過區間首尾相接
此時使用記憶化搜索實現,其實是不容易的
典型例題是能量項鏈
樹形dp
樹型動態規劃就是在“樹”的數據結構上的動態規劃
數位dp
數位dp是一種計數用的dp,一般就是要統計一個區間[le,ri]內滿足一些條件數的個數。所謂數位dp,字面意思就是在數位上進行dp咯。數位還算是比較好聽的名字,數位的含義:一個數有個位、十位、百位、千位…數的每一位就是數位啦!
倍增dp
對于只考慮首位狀態的DP,考慮用倍增優化
插頭dp
基于聯通性的狀態壓縮動態規劃是一類很典型的狀態壓縮動態規劃問題,因為其壓縮的本質并不像是普通的狀態壓縮動態規劃那樣用0或者1來表示未使用、使用兩種狀態,而是使用數字來表示類似插頭的狀態,因此,它又被稱作插頭DP。
插頭DP本質上是一類狀態壓縮DP,因此,依然避免不了其指數級別的算法復雜度,即便如此,它依然要比普通的搜索算法快很多。
斜率優化與四邊形不等式優化
我們知道,有些DP方程可以轉化成DP[i]=f[j]+x[i]的形式,其中f[j]中保存了只與j相關的量。這樣的DP方程我們可以用單調隊列進行優化,從而使得O(n^2)的復雜度降到O(n)。
四邊形不等式是一種比較常見的優化動態規劃的方法
環+外向樹上的dp
想一想也知道,只要有一個人討厭另外一個人,這兩個人最后是不會在一起的。
n個人n條邊(圖不保證聯通),這就是一個環加外向樹森林
不能同時取一條邊上的兩個人,用DP來實現
9、計算幾何
計算幾何基礎
三位計算幾何初步
數學上,立體幾何(Solid geometry)是3維歐氏空間的幾何的傳統名稱—- 因為實際上這大致上就是我們生活的空間。一般作為平面幾何的后續課程。立體測繪(Stereometry)處理不同形體的體積的測量問題:圓柱,圓錐, 錐臺, 球,棱柱, 楔, 瓶蓋等等。 畢達哥拉斯學派就處理過球和正多面體,但是棱錐,棱柱,圓錐和圓柱在柏拉圖學派著手處理之前人們所知甚少。尤得塞斯(Eudoxus)建立了它們的測量法,證明錐是等底等高的柱體積的三分之一,可能也是第一個證明球體積和其半徑的立方成正比的。
梯形剖分與三角形剖分
傳說把一個多邊形按照順時針(或者逆時針)旋轉,相鄰兩個點分別作x軸的垂線(并且這兩個點相連),就構成了梯形,然后定義從點在x軸方向上左到右為正(或者為負),得到n個梯形,把面積加起來就構成了多邊形面積,這種剖分就是梯形剖分。
三角剖分是代數拓撲學里最基本的研究方法。 以曲面為例, 我們把曲面剖開成一塊塊碎片,要求滿足下面條件: (1)每塊碎片都是曲邊三角形; (2)曲面上任何兩個這樣的曲邊三角形,要么不相交,要么恰好相交于一條公共邊(不能同時交兩條或兩條以上的邊)。 [1]
凸包
凸包(Convex Hull)是一個計算幾何(圖形學)中的概念。
在一個實數向量空間V中,對于給定集合X,所有包含X的凸集的交集S被稱為X的凸包。X的凸包可以用X內所有點(X1,…Xn)的凸組合來構造.
在二維歐幾里得空間中,凸包可想象為一條剛好包著所有點的橡皮圈。
用不嚴謹的話來講,給定二維平面上的點集,凸包就是將最外層的點連接起來構成的凸多邊形,它能包含點集中所有的點。
旋轉卡殼
”旋轉卡殼“是很形象的說法,因為根據我們枚舉的邊,可以從每個維護的點畫出一條或平行或垂直的直線,為了確保對于當前枚舉的邊的最優性,我們的任務就是使這些直線能將凸包正好卡住。
半平面交
半平面:平面上的直線及其一側的部分。
pick定理
皮克定理是指一個計算點陣中頂點在格點上的多邊形面積公式,該公式可以表示為S=a+b÷2-1,其中a表示多邊形內部的點數,b表示多邊形落在格點邊界上的點數,S表示多邊形的面積。
掃描線
掃描線一般運用在圖形上面,它和它的字面意思十分相似,就是一條線在整個圖上掃來掃去,它一般被用來解決圖形面積,周長等問題。
10、搜索相關
dfs、bfs
深度優先搜索是一種在開發爬蟲早期使用較多的方法。它的目的是要達到被搜索結構的葉結點(即那些不包含任何超鏈的HTML文件) 。在一個HTML文件中,當一個超鏈被選擇后,被鏈接的HTML文件將執行深度優先搜索,即在搜索其余的超鏈結果之前必須先完整地搜索單獨的一條鏈。深度優先搜索沿著HTML文件上的超鏈走到不能再深入為止,然后返回到某一個HTML文件,再繼續選擇該HTML文件中的其他超鏈。當不再有其他超鏈可選擇時,說明搜索已經結束。 [1]
寬度優先搜索算法(又稱廣度優先搜索)是最簡便的圖的搜索算法之一,這一算法也是很多重要的圖的算法的原型。Dijkstra單源最短路徑算法和Prim最小生成樹算法都采用了和寬度優先搜索類似的思想。其別名又叫BFS,屬于一種盲目搜尋法,目的是系統地展開并檢查圖中的所有節點,以找尋結果。換句話說,它并不考慮結果的可能位置,徹底地搜索整張圖,直到找到結果為止。
A*算法
A算法,A(A-Star)算法是一種靜態路網中求解最短路徑最有效的直接搜索方法,也是解決許多搜索問題的有效算法。算法中的距離估算值與實際值越接近,最終搜索速度越快。
迭代加深搜索(IDA*)、雙向廣搜
IDA算法不是基于迭代加深的A算法。
迭代加深只有在狀態呈指數級增長時才有較好的效果,而A就是為了防止狀態呈指數級增長的。
IDA算法其實是同時運用迭代加深與全局最優性剪枝。
IDA算法發明出來后,可以應用在生活的各個方面,小到你看電腦的屏幕節能,大到LED燈都采用了此算法,加進了LED燈的研發,舉個例子,計算機的節能,使用了IDA算法根據光亮調整亮度,可以減少藍光輻射以保護長時間盯著電腦的人們,保護了諸如程序員,OIer等等。
所謂雙向搜索指的是搜索沿兩個方向同時進行:正向搜索:從初始結點向目標結點方向搜索;逆向搜索:從目標結點向初始結點方向搜索;當兩個方向的搜索生成同一子結點時終止此搜索過程。
11、特殊算法
莫隊算法、樹上莫隊
莫隊算法的思路是,離線情況下對所有的詢問進行一個美妙的SORT (),然后兩個指針l,r(本題是兩個,其他的題可能會更多)不斷以看似暴力的方式在區間內跳來跳去,最終輸出答案。 掌握一個思想基礎:兩個詢問之間的狀態跳轉。
樹上莫隊,顧名思義就是把莫隊搬到樹上。
模擬退火
模擬退火算法來源于固體退火原理,是一種基于概率的算法,將固體加溫至充分高,再讓其徐徐冷卻,加溫時,固體內部粒子隨溫升變為無序狀,內能增大,而徐徐冷卻時粒子漸趨有序,在每個溫度都達到平衡態,最后在常溫時達到基態,內能減為最小。
爬山算法
爬山算法是一種局部擇優的方法,采用啟發式方法,是對深度優先搜索的一種改進,它利用反饋信息幫助生成解的決策。 屬于人工智能算法的一種。
隨機增量算法
隨機增量算法是計算幾何的一個重要算法,它對理論知識要求不高,算法時間復雜度低,應用范圍廣大。 增量法 (Incremental Algorithm) 的思想與第一數學歸納法類似,它的本質是將一個問題化為規模剛好小一層的子問題。 解決子問題后加入當前的對象。
12、其他重要工具與方法
模擬與貪心
模擬的缺點是運算量大,效率低下。往往需要剪枝才能AC。
貪心算法(又稱貪婪算法)是指,在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,算法得到的是在某種意義上的局部最優解 [1] 。
貪心算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇 [1] 。
二分法、三分法(求偏導)
二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。但是,折半查找要求線性表必須采用順序存儲結構,而且表中元素按關鍵字有序排列。 [1]
三分法是二分法的變種,他最基本的用途是求單峰函數的極值點。
分治、CDQ分治
分治,字面上的解釋是“分而治之”,就是把一個復雜的問題分成兩個或更多的相同或相似的子問題,再把子問題分成更小的子問題……直到最后子問題可以簡單的直接求解,原問題的解即子問題的解的合并。在計算機科學中,分治法就是運用分治思想的一種很重要的算法。分治法是很多高效算法的基礎,如排序算法(快速排序,歸并排序),傅立葉變換(快速傅立葉變換)等等。
CDQ分治主要思想還是分治的思想,即遞歸處理小范圍信息,之后將處理的信息合并上傳。 一般來說,都是先處理左區間,之后用左區間更新右區間,順便更新答案,然后處理右區間,之后再將兩個區間的信息合并。
高精度
高精度算法(High Accuracy Algorithm)是處理大數字的數學計算方法。在一般的科學計算中,會經常算到小數點后幾百位或者更多,當然也可能是幾千億幾百億的大數字。一般這類數字我們統稱為高精度數,高精度算法是用計算機對于超大數據的一種模擬加,減,乘,除,乘方,階乘,開方等運算。對于非常龐大的數字無法在計算機中正常存儲,于是,將這個數字拆開,拆成一位一位的,或者是四位四位的存儲到一個數組中, 用一個數組去表示一個數字,這樣這個數字就被稱為是高精度數。高精度算法就是能處理高精度數各種運算的算法,但又因其特殊性,故從普通數的算法中分離,自成一家。
離線
離線算法( off line algorithms),是指基于在執行算法前輸入數據已知的基本假設,也就是說,對于一個離線算法,在開始時就需要知道問題的所有輸入數據,而且在解決一個問題后就要立即輸出結果。
ST表
ST表 (Sparse Table, 稀疏表 )是一種簡單的數據結構,主要用來解決 RMQ (Range Maximum/Minimum Query,區間最大/最小值查詢 )問題。 它主要應用 倍增 的思想,可以實現 預處理、 查詢。
13、STL
map
作為關聯式容器的一種,map 容器存儲的都是 pair 對象,也就是用 pair 類模板創建的鍵值對。其中,各個鍵值對的鍵和值可以是任意數據類型,包括 C++ 基本數據類型(int、double 等)、使用結構體或類自定義的類型。
priority_queue
不出所料,priority_queue 容器適配器定義了一個元素有序排列的隊列。默認隊列頭部的元素優先級最高。因為它是一個隊列,所以只能訪問第一個元素,這也意味著優先級最高的元素總是第一個被處理。但是如何定義“優先級”完全取決于我們自己。如果一個優先級隊列記錄的是醫院里等待接受急救的病人,那么病人病情的嚴重性就是優先級。如果隊列元素是銀行的借貸業務,那么借記可能會優先于信貸。
set
C++ STL 之所以得到廣泛的贊譽,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封裝了許多復雜的數據結構算法和大量常用數據結構操作。vector封裝數組,list封裝了鏈表,map和set封裝了二叉樹等,在封裝這些數據結構的時候,STL按照程序員的使用習慣,以成員函數方式提供的常用操作,如:插入、排序、刪除、查找等。讓用戶在STL使用過程中,并不會感到陌生。
關于set,必須說明的是set關聯式容器。set作為一個容器也是用來存儲同一數據類型的數據類型,并且能從一個數據集合中取出數據,在set中每個元素的值都唯一,而且系統能根據元素的值自動進行排序。應該注意的是set中數元素的值不能直接被改變。C++ STL中標準關聯容器set, multiset, map, multimap內部采用的就是一種非常高效的平衡檢索二叉樹:紅黑樹,也成為RB樹(Red-Black Tree)。RB樹的統計性能要好于一般平衡二叉樹,所以被STL選擇作為了關聯容器的內部結構。
bitset
bitset 模板類由若干個位(bit)組成,它提供一些成員函數,使程序員不必通過位運算就能很方便地訪問、修改其中的任意一位。
rope
rope 不屬于標準 STL,屬于擴展 STL,來自 pb_ds 庫 (Policy-Based Data Structures)。
14、非常見算法
朱劉算法
朱劉算法是一個 O (nm) 的算法。 當然,還有Tarjan巨神的 O (n log n) 的算法。
弦圖與區間圖
定義弦為一個環中連接不相鄰兩個點的邊。
弦圖為一個圖,其中任意一個長度大于3的環都包含至少一條弦。
換句話說:弦圖最大的沒有弦的環大小小于3
區間圖著色問題
本篇文章已經接近尾聲了,最后來紀念一下C語言、UNIX之父——丹尼斯·麥卡利斯泰爾·里奇(Dennis MacAlistair Ritchie)
丹尼斯·里奇(1941年9月9日-2011年10月12日),C語言之父,UNIX之父。曾擔任朗訊科技公司貝爾實驗室下屬的計算機科學研究中心系統軟件研究部的主任一職。1978年與布萊恩·科爾尼干(Brian W. Kernighan)一起出版了名著《C程序設計語言(The C Programming Language)》。此書已翻譯成多種語言,被譽為c語言的圣經。2011年10月12日(北京時間為10月13日),丹尼斯·里奇去世,享年70歲。
普通年輕人可能都要搖頭。丹尼斯·里奇是誰?
丹尼斯·里奇不像某位來自硅谷,精致的和少年得志的億萬富翁,穿著簡約黑色的高領毛衣在站滿粉絲的屋子里,演示新酷產品和惡意攻擊對手。
不,丹尼斯·里奇是一位胡子有些凌亂的計算機科學家,他穿著羊毛衫坐在一間凌亂的辦公室里。
和喬布斯在大學輟學不同,他畢業于哈佛大學,有物理學和應用數學的博士學位。他工作于新澤西的 AT&T 貝爾實驗室,而不是閃閃發光的硅谷。
雖然存在宗教和意識形態的差異。但我們虧欠丹尼斯·里奇很多,超出我們的想象。沒有他的貢獻,現在我們沒法用個人計算機,成熟的軟件應用甚至是互聯網。
沒有 Android 智能手機,沒有昂貴的 DVR 和流媒設備,沒有喬布斯和蘋果創造令人驚嘆的 Mac 和 iPad。
沒有微軟的 Windows 10 和 Surface Book。
沒有云計算、沒有 AWS(亞馬遜網絡服務,Amazon Web Services),沒有 Azure(微軟云)。
沒有“為 XX 而生的應用程序”,也沒有互聯網這個東西。
向丹尼斯·里奇致敬 —— 感謝他帶給我們這些技術,讓我們可以成為今天的專家。
總結
以上是生活随笔為你收集整理的精心整理2万字c++知识点的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spoon安装步骤
- 下一篇: vcpkg工具+vs2019