市赛前第三次培训讲义
An-Li Alt Ting October 6, 2014
Contents
1 Preface 2
2 树 2
2.1 Problems on OJs . . . 3
2.2 二元树 . . . 3
2.3 二元搜寻树 . . . 3
2.3.1 Problems on OJs . . . 4
2.4 二分索引樹 . . . 4
2.4.1 Problems . . . 5
2.4.2 Problems on OJs . . . 5
2.5 线段树 . . . 5
2.5.1 Time Compelexity . . . 6
2.5.2 Problems on OJs . . . 7
2.6 堆积 . . . 8
2.6.1 優先隊列 . . . 8
2.7 并查林 . . . 8
2.7.1 Problems on OJs . . . 9
3 图论常见问题 10 3.1 拓扑排序 . . . 10
3.1.1 Methods those generate a TS . . . 10
3.1.2 Problems on OJs . . . 11
3.1.3 Related . . . 11
3.2 單源最短路徑 . . . 11
3.2.1 Dijkstra’s Algorithm . . . 11
3.2.2 Bellman-Ford Algorithm . . . 12
3.2.3 Shortest Path Faster Algorithm (SPFA) . . . 12
3.3 全点对最短路径. . . 13
3.3.1 Floyd-Warshall Algorithm . . . 13
3.4 最小生成树 . . . 13
3.4.1 最小瓶頸生成樹 . . . 14
3.4.2 Prim’s Algorithm . . . 14
3.4.3 Kruskal’s Algorithm . . . 15
3.5 联通元件 . . . 15
3.5.1 強連通分量 . . . 15
3.6 雙連通元件 . . . 16
3.6.1 割點 . . . 17
3.6.2 割邊 . . . 18
3.6.3 Kosaraju’s Algorithm . . . 18
3.6.4 Tarjan’s Algorithm . . . 19
3.6.5 2-satisfiability . . . 19
4 C++ 概论 20 4.1 输入输出 . . . 20
4.2 类别 . . . 20
5 References 20
1 Preface
树的相关定义在学术界多元而混乱,竞赛时以保留原理为主。
这次讲义太厚了,所以把一些东西删掉了,只留下比较难记得的;删掉的讲师口 头补。
2 树
树(tree),是一种数据结构。
结点(node):一个独立的单位。
连结(link):两个结点v、w 之间的连接关系;v、w之间的连结被记为 (v, w)。
树(tree):连结联通所有结点而不形成环的结点与连结集合,点为空集合的树又 称为空。
有根树(rooted tree):被指定且尽被指定了一个结点作为根的树。
结点的深度(depth):有根树从根结点要存取到目标结点所需要经过的连结数目;
v 的深度被记为d(v)。
结点的子结点(child node)与父结点(parent node):(v, w) 存在且 d(v) + 1 = d(w) 时,称 v 为w 的父结点,w 为 v 的子结点。
结点的度数(degree):结点的子结点个数;v 的度数被记为δ(v)。
结点的子树(sub-tree):以任何一个自己的子结点为根,与该子结点的子树组成的 树。
树的深度:最深子孙的深度。
2.1 Problems on OJs
Step5OJ 0040 Ch3-4. 瀚瀚肥皂樹 UVaOJ 112 Tree Summing
2.2 二元树
二元树(binary tree、二叉树)。
二元树:空或有两个二元子树的结点。
非空二元树的左子树(left sub-tree)与右子树(right sub-tree):非空二元树的两 个子树分别被称为左子树与右子树。
非空二元树的度数:非空子树个数。
其余定义与树类似,不另赘述。
在这种定义下,严格来说,二元树不是一种树。
完全二元树(complete binary tree):口头解释。
满二元树(full binary tree):口头解释。
2.3 二元搜寻树
二元搜寻树(binary search tree)。
二元搜寻树:对于任意结点 v,v 的左子结点键值总是比 v 的键值小,v 的右子结 点键值总是比v 的键值大的二元树。
Example of Order statistic tree 1-based Binary Search Tree.
Methods: insert, find_by_order, order_of_key.
C++98 code:
const int max_key =1 < <10;
int t [2* max_key ];
int insert ( int *tree , int k){
for ( int v= max_key +k;v;v > >=1) tree [v ]++;
}
int find_by_order ( int *tree , int order ){
int v =1;
while (v- max_key <0){
if( order < tree [2* v ]){
v =2* v;
} else {
order -= tree [2* v];
v =2* v +1;
} }
return v- max_key ; }
int order_of_key ( int *tree , int k){
int x =0;
for ( int v= max_key +k;v;v > >=1) if(v &1)
x+= tree [v -1];
return x;
}
2.3.1 Problems on OJs
HOJ 107 程式順序問題
HOJ 126 交換字卡 HOJ 315 城市規劃
2.4 二分索引樹
Binary Indexed Tree (B.I.T.) 二分索引樹,又稱樹狀數組或 Fenwick tree。
用於求取前綴累積,並支持單點更新,更新方式為加上一值。
1-based close inteval.
const int mn =1 < <10;
int a[ mn +1]; // 1- based array . // Prefix accumulate query
int query ( int index ){
int x =0;
while (1 <= index ){
x+=a[ index ];
/*
Shift to the next vertex ,
which presents the previous interval .
*/
index -= index &- index ; }
return x;
}
void update ( int index , int key ){
while ( index <= mn ){
a[ index ]+= key ; /*
Shift to the next vertex ,
which presents the interval which contains current interval .
*/
index += index &- index ; }
}
2.4.1 Problems
Classic Inversion 逆序數對
2.4.2 Problems on OJs HOJ 058 矩陣和
2.5 线段树
Segment Tree 線段樹,是一種用於儲存一維陣列的資料結構。支援高效地求取「區間
累積」,並在允許「惰性賦值」的情況下支援高效的「區間修改」。其累積運算必須符
合結合律;與sparse table 相比,其累積運算不需要符合冪等律。
2.5.1 Time Compelexity Build:O(n)
Update by range:O(log n)
Query accumulation by range:O(log n)
線段樹是一棵二元搜尋樹,其核心價值是靜態 D&C。
令樹根的鍵值是整個陣列的累積。如果陣列的大小等於一,則此鍵值就是該陣列 唯一元素的值;否則將此陣列切割為兩個陣列,並以此兩個陣列分別建立左右子樹,
則此鍵值就是子樹的鍵值和。如果在建立時,盡可能的從中位數切割陣列,那麼這棵 線段樹深度的量級就會屬於 log n。
求取一個區間累積時,可以利用樹上的節點的值,組合出該問題得答案,即是 DP。 一個常見的 top-down method 是:如果該區間就等同整個陣列,則樹根的鍵值就是答 案。否則從將母問題依照樹建立時的切割方式切割問題,並平行地將子問題交付給兩 個子樹解決,再行組合。這樣的時間複雜度也屬於O(log n)。
執行一個區間修改時,即是像查表求累積時一樣的分割問題。不同的是,該區間 就等同整個陣列時,那麼就直接修改樹根的值,並在樹根留下修改的標記,待下次操 作時,若需要存取到子樹,再將標記下傳。
有關於使用陣列建立二元樹時,所需空間的探討:
設根節點深度為0,則深度為 d 的完美二元樹有2d 個葉子,並有2d+1−1個節點。
換句話說,若要開一個值域大小達 n 的線段樹,則需要 2⌈log(n)⌉+1−1 個節點。
然而 2⌈log(n)⌉+1−1 <4n,所以當編程時間不允許詳細計算時,可以直接調用 4n 的空
間。
範例:區間求和與區間加上定值
多數版本的線段樹,查詢是帶有更新的,而更新更是不外乎查詢。
查詢與更新的行為是如此相似,何不讓這兩種操作合而為一呢?
如果每次的需求都是更新並查詢,這麼作更是毋庸置疑。
而如果不想更新,就加上零就好;如果不想查詢,查到了不要用就好。
對數時間加上對數時間,還是對數時間。
typedef long long ll;
const int d=17 ,n=1<<d;
ll a [2*n -1] , tag [2*n -1] ,* A=a+n -1;
void build (){
for ( int v=n -2;v >=0;v - -) a[v]=a [2* v +1]+ a [2* v +2];
}
ll query ( int f, int l,ll k=0 , int v=0 , int h=0 , int t=n ){
if(l <=h||t <=f)
return 0;
if(f <=h&&t <=l){
a[v ]+=(t-h)*k;
tag [v ]+= k;
return a[v];
}
query (h,t, tag [v] ,2*v+1 ,h,h+t > >1);
query (h,t, tag [v] ,2*v+2 ,h+t >>1,t );
tag [v ]=0;
ll x =0;
x+= query (f,l,k ,2* v+1 ,h,h+t > >1);
x+= query (f,l,k ,2* v+2 ,h+t >>1,t);
a[v]=a [2* v +1]+ a [2* v +2];
return x;
}
此線段樹用到的加法與乘法中,有用到的代數性質有:
加法有結合律:值被累積的順序並不重要。
加法有單位元:以零代表無,或以加零代表不加。
這說明,只要符合結合律,有單位元的二元運算,都可以作為此線段樹中的二元運 算。
min、max、gcd、lcm 都是符合條件的二元運算。
const int d=17 ,n=1<<d;
ll a [2*n -1] , tag [2*n -1] ,* A=a+n -1;
void build (){
for ( int v=n -2;v >=0;v - -) a[v]=a [2* v +1]+ a [2* v +2];
}
ll query ( int f, int l, int k=0 , int v=0 , int h=0 , int t=n,ll ac =0){
if(l <=h||t <=f) return 0;
if(f <=h&&t <=l) return a[v ]+=(t -h)*k, tag [v ]+=k,a[v ]+(t-h)* ac;
ll x =0;
x+= query (f,l,k ,2* v+1 ,h ,(h+t)/2 , ac+ tag [v ]);
x+= query (f,l,k ,2* v+2 ,(h+t)/2 ,t,ac+ tag [v ]);
a[v]=a [2* v +1]+ a [2* v +2]+(t-h)* tag [v];
return x;
}
2.5.2 Problems on OJs
HOJ 012 矩形面積覆蓋
HOJ 013 矩形周長
HOJ 144 海綿寶寶之吹泡泡
IOICJ 019 胖胖兮的書架 POJ 2104 K-th Number
POJ 3468 A Simple Problem with Integers Step5 0132 汁男區間
Step5 0150 花匠
TIOJ 1305 啊嘶起啦集合
2.6 堆积
2.6.1 優先隊列
Priority Queue 優先隊列。
Problems on OJs HOJ 241 Dispatching
2.7 并查林
Union-Find Forest (UFF) 併 查 林, 是 一 個 資 料 結 構, 可 以 用 來 解 決 互 斥 集
(Disjoint-sets)的部份問題。
一個 UFF 能表達一組互斥集,並允許兩種基本操作,聯合(合併)與查找。
聯合是這個結構的輸入,即指定兩個集合聯合起來。查找是這個結構的查詢,即給定 一個元素,返回一個與之同集的元素。並保證下次聯合以前,多次對於同集內元素的 查找結果一致,這樣的特性可以讓我們確定兩個元素是否在同一個集合內。
實作方式:
UFF 是一個森林,並且允許隨時新增樹。每一棵樹表達一個集合,並以一棵樹 的根代表一棵樹。首先定義根的父節點是其本身,對於每一個節點紀錄其父節點,就 可以建構出一棵允許向根探索的樹。
有關於查找:給定一個節點,求其樹根,即是不斷向根探索,直到找到一個父節 點為其本身的節點,那個節點就是根了。
有關於聯合:因為以一棵樹的根代表一個集合,所以可以找到兩個樹的根,來代 表兩個集合。將這兩個根中的其中一個根的父節點指定為另外一個,這兩棵樹就會聯 合起來,代表父節點也是同一個,所以這兩個集合也被聯合起來了。至於選擇哪一個 節點作為樹根,只會影響效率,而不會影響到正確性。
優化方式:
Path Compression Union by Rank
解題技巧:
一、欲聯合之兩集,在公理上絕對互斥,謂之矛盾。
二、保留條件與矛盾條件必須存在交集。
通常讓保留條件盡量完全,矛盾條件就不會需要太多。
struct vertex { vertex * parent ;
vertex (): parent ( this ){}
vertex * root (){
// Find : find the root of the tree . if( parent == this )
return this ; else {
parent = parent -> root ();
// Path compression return parent ;
} }
vertex & operator =( vertex &v){
// Union : union the tree with v.
root () -& parent =v. root ();
return * this ; }
bool operator ==( vertex &v){
// Compare
return root ()== v. root ();
} };
競賽模板:
競賽模板與原版相比,在指定運算時所回傳的參考有所不同,但是對於互斥集的 本質來說是等價的。
此模板幾乎萬用。
struct sv{
sv*p;
sv (): p( this ){}
sv*r (){ return p == this ?p:( p=p ->r ());}
sv& operator =( sv&v){ return *( r()->p=v.r ());}
bool operator ==( sv&v){ return r ()== v.r ();}
};
2.7.1 Problems on OJs HOJ 078 食物鏈
HOJ 112 生物實驗 POJ 1182食物鏈 POJ 2492 A Bug’s Life
POJ 2524 Ubiquitous Religions IOICJ 067 慘兮兮
Step5 0118 勝利的宣言 TIOJ 1312 家族
TIOJ 1798 Can You Arrive?
ZJ a089 NOI2002 Day1.1. 银河英雄传说
3 图论常见问题
3.1 拓扑排序
Topological Sort (TS) 拓撲排序。
一張圖存在 TS 若且唯若為DAG,DAG 的判斷可以使用TS。 G 與G’ 的 TSs 可以互相轉換。
3.1.1 Methods those generate a TS 一、Greedy:
持續探訪 δ+(v) = 0 的點,每次探訪一個點時,將所有 (v, w) ∈ E 刪去,直到沒
有 δ+(v) = 0 的點為止。「探訪到所有點」若且唯若「存在拓撲排序」。若存在拓撲排
序,則探訪順序即為拓撲排序。
二、DFS:
若存在拓撲排序,對於每一個點的離開時間戳記由晚到早排,即為拓撲排序。
或者
遍歷圖 G。探訪到 v 時,先搜索 w ((w, v) ∈ E),再選擇 v。「深搜堆棧中不重複 出現任一點」若且唯若存在「拓撲排序」。若存在拓撲排序,則選擇順序即為拓撲排
序。
3.1.2 Problems on OJs HOJ 075 貼磁磚
HOJ 141 海綿寶寶之製作蟹堡 (拓撲排序)
POJ 1094 Sorting It All Out POJ 3687 Labeling Balls
3.1.3 Related
Kosaraju’s Algorithm is an algorithm generating TS of SCCs。
3.2 單源最短路徑
Single-Source Shortest Path (SSSP) 單源最短路徑。
Algorithms those solve SSSP Dijkstra’s Algorithm
Bellman-Ford Algorithm
Shortest Path Faster Algorithm (SPFA)
3.2.1 Dijkstra’s Algorithm
Dijkstra’s Algorithm 有類似於 BFS 的思路,BFS 是深度低的優先搜索,Dijkstra’s Algorithm則是距離近的優先搜索,BFS可以視為 Dijkstra’s Algorithm 的特例。
Time complexity
使用 priority queue:O(|E|log|E|) 使用 binary heap:O(|E|log|V|)
使用 Fibonacci heap:O(|E|+|V|log|V|) (from Wikipedia) Problems on OJs
HOJ 138 海綿寶寶之我要吃美味蟹堡 (最短路)
HOJ 305 買醬油 VI 之四則運算問題
3.2.2 Bellman-Ford Algorithm
定義「以所有邊v, w 鬆弛 w」為「鬆弛一回合」,持續 |V| −1 回合,則完成算法。
Time complexity: O(|V| × |E|) Problems on OJs
HOJ 104 環狀捷運系統問題
HOJ 139 海綿寶寶之海之霸 (最短路負權)
3.2.3 Shortest Path Faster Algorithm (SPFA)
Shortest Path Faster Algorithm (SPFA),為一個從 Bellman-Ford Algorithm 改進而來 的演算法。
從起點開始操作。不斷鬆弛與之相鄰的點,並將成功被鬆弛的點加到佇列中,直 到所有相鄰的點都被鬆弛,即鬆弛佇列中的下一個點。直到佇列為空,則結束。
Time complexity: O(|V| × |E|) Average time complexity: O(|E|) Properties
Detecting negative cycle
C 為單點入queue 次數,∃ C s.t. |V| ≤C,則有負環。
C 為queue push 次數,|V|2 ≤C,則有負環。
Problems
Classic Minimum Ratio Cycle Problems on OJs
HOJ 009 大麥克的世界旅行
3.3 全点对最短路径
All-pairs Shortest Path (APSP) 全点对最短路径。
Algorithms those solve APSP Floyd-Warshall Algorithm
3.3.1 Floyd-Warshall Algorithm 檢查連通
∃ di,i <∞
Negative cycle detecting 偵測負環
∃ di,i <0 Problems
Minimum Weight Circuit最小圈 Problems on OJs
HOJ 005 漢米頓的麻煩
HOJ 015 搬家
3.4 最小生成树
Minimum spanning tree (MST) 最小生成樹,又稱作 minimum weight spanning tree,
是一種使權重和最小的生成樹。另外,MST也是 MBST。 Possible multiplicity 可複性
一張圖可能有多個不同的 MST。 Uniqueness 唯一性
無等權圖有唯一MST。
”If each edge has a distinct weight then there will be only one, unique minimum spanning tree.” - Wikipedia
Cycle property 環性質
對於任意環 C,權最大邊不屬於 MST。
”For any cycle C in the graph, if the weight of an edge e of C is larger than the weights of all other edges of C, then this edge cannot belong to an MST.” - Wikipedia
Cut property 割性質
對於任意割 C,權嚴格最小邊屬於 MST。
”For any cut C in the graph, if the weight of an edge e of C is strictly smaller than the weights of all other edges of C, then this edge belongs to all MSTs of the graph.” - Wikipedia
Algorithms those generate an MST Prim’s Algorithm
Kruskal’s Algorithm Problems on OJs HOJ 063 宅心仁厚
HOJ 140 海綿寶寶之偷賣美味蟹堡 (最小生成樹)
HOJ 304 買醬油 V 之腳踏車問題
HOJ 316 Point group POJ 1789 Truck History
3.4.1 最小瓶頸生成樹
Minimum Bottleneck Spanning Tree 最小瓶頸生成樹。
3.4.2 Prim’s Algorithm
Prim’s Algorithm 是一種求取 MST的演算法。
將任意點指定給子樹 T,持續將與 T 相鄰的點中邊權最小的點加入 T,直到沒有 點與 T 相鄰。
Time complexity:
使用鄰接鏈表與陣列:O(|V|2)
使用鄰接鏈表與優先隊列:O(|E| log |E|)
3.4.3 Kruskal’s Algorithm
Kruskal’s Algorithm 是一種求取 MST的演算法。
對於一張無向圖,持續從 E 中取得邊權最小並且該兩點位連通的邊,該生成樹為 MST。
判斷兩子圖是否連通,可以使用 union-find tree。
3.5 联通元件
3.5.1 強連通分量
Strongly Connected Component (SCC) 強連通分量(臺灣地區又稱之強連通元件)。
Properties
DAG 的 SCC 數量與點數相當。
有大於一的強連通分量,若且唯若有環。
Algorithms Decomposing a Graph to SCCs Kosaraju’s Algorithm
Tarjan’s Strongly Connected Components Algorithm Problems
2-satisfiability Problems on OJs HOJ 055 情報網
HOJ 147 海綿寶寶之蟹堡餐飲聯盟 (2-SAT)
HOJ 330 Crayfish
POJ 2186 Popular Cows Step5OJ 0141噴射裝置
3.5.2 雙連通元件
Biconnected Component (BCC) 雙連通元件,分為 vertex biconnected 點雙連通,與 edge biconnected 邊雙連通。
Vertex Biconnected (VBCC) 點雙連通元件
定義:滿足「刪除其中任意點,仍保持連通」的極大連通子圖。
VBCC 中沒有對於該C 的 CV。
VBCC 中任兩相異點中,存在至少兩條點互斥路徑。
所有點雙連通元件中包含所有圈。
圖中由割點分開包含相鄰割點的那些子圖,就是所有的 VBCC。
割點會被多個VBCC 共用。
點雙連通元件之間沒有任何身份相同或者意義相同的邊。
身份相同是指e 與 e 本身,意義相同是指 e(v,w) 與 f(v,w)。 所以點雙連通元件是一種對邊的分類。
Algorithm 線上作法:
使用堆疊。建立任意一條有向邊 (v, w) 則 push (v, w)。dfs (w) 以後,如果 w 令 v 為
割點,則 pop直到最後 (v, w)出棧,出棧的這些點即是一個 VBCC。
Edge Biconnected (EBCC) 邊雙連通元件 EBCC 中沒有CE。
EBCC 中任兩相異點中,存在至少兩條邊互斥路徑。
所有邊雙連通元件中包含所有環。
在母圖上,邊雙連通元件之間由橋連通。若把邊雙連通元件視為點,則該圖是一 棵樹。
Algorithm
將圖上的 CE都移除,剩下的連通子圖即是所有的 EBCC。
線上作法:
In Tarjan’s Algorithm: 使用堆疊。進入任意點 v,則 push v。離開點 v 時,如果
index(v) =lowlink(v),則 pop直到最後 v 出棧,出棧的這些點即是一個 EBCC。
Examples
VBCC but not EBCC 2 1
1 2
EBCC but not VBCC 5 6
1 2 2 3 3 1 3 4 4 5 3 5
Algorithms Tarjan’s Algorithm
DFS一連通圖 G,可以將邊賦予方向,得到 G;G的 EBCC 將對應到G’ 的SCC。
Problems on OJs
POJ 2942 Knights of the Round Table 點雙連通元件。
POJ 3177 Redundant Paths 數學構造邊雙連通圖。
POJ 3352 Road Construction
數學構造邊雙連通圖,同 POJ 3177。 TIOJ 1798 Can You Arrive?
3.5.3 割點
Cut-vertex 割點(articulation points 關節點)。
Tarjan’s Cut-vertex Algorithm
對於一個連通圖,選定任意點為根深搜。
對於根節點 r:δ(r)>1→r∈CV(V)
對於非根節點v:lowlink(w)≥index(v)→v ∈CV(V)
3.5.4 割邊
Cut-edge 割邊(bridge 橋)。
Tarjan’s Cut-edge Algorithm
對於一個連通圖,選定任意點為根深搜。
lowlink(w)> index(v)→e(v, w)∈CE(E)
3.5.5 Kosaraju’s Algorithm
可以使用 Kosaraju’s Algorithm求出 SCCs 的 TS。
若原圖為有向有環圖,則此排序有性質:為令非法邊最少的排序。
求 SCCs 與縮成 DAG 是等價的。DAG 存在拓撲排序,對於任意 SCCs 的拓撲排 序,一定有某種意義上的等價序列在原圖的子序列上。DFS 過程中可能跨越多個 SCC。但是如果把(v, w) 映射到(w, v),射為G′,沿著原本的DFS順序再 DFSG′ 一 次,那自然都不會跨越多個 SCC,在 DFS 一個元件的時候,就可以映射 SCC(v) 到 Ci。
C++98 code
vector <int >G[mv],RG[mv ];
void ae( int v, int w){
G[v]. push_back (w);
RG[w]. push_back (v);
}
bool vs[mv ];
int vc[mv ];
vector <int > vout ;
void dfs ( vector <int >*g, int v, int c = -1){
if(vs[v ]++) return ; vc[v]=c;
for ( int i =0;i<g[v]. size (); i ++) dfs (g,g[v][i],c);
if(g==G)
vout . push_back (v);
}
void scc (){
memset (vs ,0 , sizeof vs );
for ( int i =0;i<cv;i ++) dfs (G,i);
memset (vs ,0 , sizeof vs );
int c =0;
for ( int i= vout . size () -1;i >=0;i - -) dfs (RG , vout [i],c ++);
}
3.5.6 Tarjan’s Algorithm
Tarjan’s Algorithm可以用來強連通分解有向圖,双量通分解无向图,或者列舉無向圖
的割點、割邊。
在 DFS spanning tree 中:
定義 index(v) 為:v 的 in-timestamp。
定義 lowlink(v) 為:以v 為根的子樹中;若無 backedge,則為index(v);否則為只經
過一次 backedge所能到達的節點 w 中,最小的index(w)。
Pseudocode of Tarjan’s Algorithm dfs v is
lowlink v <- index w <- timestamp <- timestamp +1 mark v as visited
for all (v,w) in E
if w is non - visited dfs w
lowlink v <- min ( lowlink v , lowlink w) else
lowlink v <- min ( lowlink v , index w) Problems on OJs
HOJ 068 征服者
3.5.7 2-satisfiability
2-satisfiability(2-SAT) 是 boolean satisfiability 的special case,屬於 P。 Transforming to SCC + TS in Θ(n)
將 P 與 ¬P 分別建點,P →Q 與 ¬Q→ ¬P 分別建邊。
「P 與 ¬P 位於同一 SCC」≡ 無解。(¬(P ⇐⇒ ¬P))
若有解,P ≡ 「P 的所在的 SCC 的拓撲排序在 ¬P 的所在的 SCC 的拓撲排序之 後」。(P ≡(¬P →P))
Related formulas
P ≡ ¬P →P
P ∨Q≡ ¬P →Q≡ ¬Q→P Hints
可以使用 Kosaraju’s Algorithm求出 SCCs 的 TS。
Problems on OJs
HOJ 147 海綿寶寶之蟹堡餐飲聯盟 (2-SAT)
4 C++ 概论
4.1 输入输出
keywords: stream
4.2 类别
5 References
Wikipedia
http://www.wikipedia.org/
感谢许多来自Wikipedia 的相关图片。
http://en.wikipedia.org/wiki/Minimum_spanning_tree http://en.wikipedia.org/wiki/2-satisfiability http://en.wikipedia.org/wiki/Order_statistic_tree
http://zh.wikipedia.org/wiki/%E5%BC%97%E6%B4%9B%E4%BC%8A%E5%BE%B7%E7%AE%97%
E6%B3%95
http://gagguy.blogspot.tw/2010/11/spfa-negative-cycle.html http://blog.csdn.net/v_july_v/article/details/6181485 http://www.csie.ntnu.edu.tw/~u91029/Path2.html
https://www.byvoid.com/blog/biconnect