算法提高課——圖論


圖論難點:問題的轉化和抽象(可看成特殊的某一類DP)

圖論與DP的聯系:

 

 

 

 

DP問題(從集合角度分析最優化問題)可以看成從F(0,0)、F(0,1)、F(1,2)......F(0,m)到F(n,m)的最長路。因此DP問題可以轉化為拓撲圖(一般DP問題的狀態間無環)上的最短(長)路。

當DP依賴關系不具有拓撲序時(即存在環時),可以將其轉化為最短路,也可以用高斯消元。

//TLE的原因常常是沒有memsert

//st數組在不同算法中的用法:

 

單源最短路的建圖方式

AcWing 1129. 熱浪

//單源最短路模型。朴素堆優化Dijkstraspfa皆可

AcWing 1128. 信使

//數據范圍較小,Floyd算法直接處理

//核心:對於每個點來說,它接收到信的時間,等於它到指揮部   的最短距離。

//跑完最短路之后找出所有最短路中的最大值,若為正無窮則說   明該點與起點不連通,輸出“-1”即可

//注意預處理時d[i][i]=0。

AcWing 1127. 香甜的黃油

//多源匯最短路問題(可用堆優化DijkstraSpfa

//分析數據范圍得知,Floyd算法會超時.所以可以枚舉每一個點作為起點時的花費

AcWing 1126. 最小花費

//注意扣除手續費的計算:

  w[i]=1-手續費i (0<w[i]<1)

  100=d[A]*w[1]*w[2]*w[3]*w[4]......

  所以為使d[A]最小,應使w[1]*w[2]*w[3]*w[4]......最大。

//令S=w[1]*w[2]*w[3]*w[4]......

logS=log(w[1]*w[2]*w[3]*w[4]......)

=logw[1]+logw[2]+logw[3]+logw[4]......

因為0<w[i]<1,所以logw[i]<0,logS<0,-logS>0。那么,為使S最大,logS就應最大,-logS就應最小。其中,-logS可以看成是-logw[i]的和。

  所以本題就可以轉化成一個最短路問題,故可以用Dijkstraspfa求解。代碼可以直接用乘法來實現三角不等式,上述只是為了說明本題運用Dijkstra或spfa的正確性。

AcWing 920. 最優乘車

//sstream讀入小技巧(原題未告知一行讀入多少數):

 

//注意這道題的特殊性:要求的是換乘次數最少的路線,而非最短路。可以將問題轉化,在處於同一路線上的站點之間連一條權值為1的邊,然后用經典最短路模型處理。因為所有的邊權都是1,所以可以直接寫BFS

AcWing 903. 昂貴的聘禮

//tap:建立虛擬源點(標為0號點),表示直接買的價格,此時應注意一共有n+1個點。

//本題需要考慮等級限制:因為等級和等級限制都不超過100,所以可以枚舉等級區間,在這個區間內進行Dijkstra,時間復雜度不超過100w。

單源最短路的綜合應用

AcWing 1135. 新年好

//最短路+DFS  6*O(m)+5!

  1. 先預處理出從1,a,b,c,d,e出發到其他所有點的單源最短路徑
  2. DFS所有擺放順序,5!,對於每種擺放順序,可以通過查表的方式算出最短距離。

//當一個數組作為函數的形參被傳入時,sizeof函數就無法正常工作,會RE。

AcWing 340. 通信線路

//最短路+二分

//定義在[0,1000001]這個區間中的性質如下:

對於區間中的某一個點,求出從1走到N,最少經過的長度大於x的邊的數量是否小於等於k。

//求出從1到N最少經過幾條長度大於x的邊:

可以將所有的邊分類:如果邊長大於x,則邊權看成1,否則邊權是0。可以用雙端隊列BFS來求從1到N的最短路。

AcWing 342. 道路與航線

//這道題的路徑有兩種,一種是邊權非負的雙向邊(道路),一種是邊權可正可負且無環的單向邊(航線)。

//本題spfa會被卡。

  1. 如果邊權非負,那么可以Dijkstra算法,時間復雜度是mlogn
  2. 如果是拓撲圖,那么不管邊權是正是負,均可按拓撲序掃描,時間復雜度是線性的

//航線一定在不同的道路連通塊之間,將每一個連通塊看成一個點。具體實現方式:

1.先輸入所有雙向道路,然后DFS出所有連通塊,計算兩個數組:id[]存儲每個點屬於哪個連通塊;vector<int> block[]存儲每個連通塊里有哪些點

2.輸出所有航線,同時統計出每個聯通塊的入度

3.按照拓撲序依次處理每個連通塊。先將所有入讀為0的連通塊的編號加入隊列中

4.每次從隊頭取出一個連通塊的編號bid

5.將該block[bid]中所有點加入堆中,然后對堆中所有點跑dijkstra算法

6.每次取出堆中距離最小的點ver

7.然后遍歷ver的所有鄰點j。如果id[ver]==id[j],那么如果j能被更新,則將j插入堆中;如果id[ver]!=id[j],則將id[j]這個連通塊的入度減一,如果減成0了,則將其插入拓撲排序的隊列中。

//體現單源最短路:

memset(dist,0x3f,sizeof dist);

  dist[S]=0;

AcWing 341. 最優貿易

//最短路算法和DP的結合(本質上DP和最短路算法是有很大交集的,絕大部分DP都可以被看成是拓撲圖上的最短路或最長路問題.)。采用類似於DP的思想,把所有從1到n的路徑看成一個集合,進行子集的划分。

//假設S1,S2…St都可以走到第K個點.那么:。dmax同理。

//DP問題所說的“無后效性”即轉化為一個表示狀態的圖時,圖上是不存在環的,但是這個問題中存在。因此可以用最短路算法處理上面的類DP問題。

//用spfa正確性:

for(迭代n-1次)

for(循環邊)用三角不等式更新

  Dijkstra算法中,每個點只出隊一次,但是在本題中一個點可以被更新多次,所以Dijkstra算法不適用於這道題。

//從1到k買入的最小值dmin[k]

  從k到n賣出的最大值dmax[k]

  答案即max(dmax[k]-dmin[k])

單源最短路的擴展應用

AcWing 1137. 選擇最佳線路

//可以建反向邊,求出從終點到每個起點的最短路的最小值

原問題:從每個起點出發,到達終點的所有路徑的最小值。

加上虛擬源點之后的問題:從虛擬源點出發,到達終點的所有路線的距離的最小值。將原問題轉化成了單源最短路問題。

AcWing 1131. 拯救大兵瑞恩

//應用拆點的思想。最短路中需要拆點,分層的題目.一般都可以用DP的方式先考慮。因為有鑰匙等因素的影響,因此f(i,j)並不能只用兩維就表示出到點(i,j)的最短距離。仿照DP的思路,我們可以再加一維。

//但是這道題並不能按照DP的方式來寫,因為一般能夠用DP方式寫的題目都需要保證在計算某個狀態之前,所有能夠更新它的狀態都已經被更新了,即其狀態與狀態之間滿足拓撲序。但是這道題某些點之間是可以相互到達的,因此存在環。所以還是要用最短路的方式來寫。

//將二維變成一維:f(x,y,state)的前兩維可以壓縮成一維

//動態規划

一、狀態表示:d(x,y,state)

1.集合:所有從起點走到(x,y)這個格子,且當前已經擁有的鑰匙是state的所有路線的集合。

2.屬性:最短距離

二、狀態計算

1.(x,y)這里有一些鑰匙,那么可以直接將所有鑰匙拿起:

2.向上下左右四個方向走。

(1)沒有門和牆

(2)有門,且有匹配的鑰匙,之后走到了(a,b):

//狀態間存在環形依賴,因此可以將DP轉化成圖論問題(BFS)

//Taps:

1.用一維數字表示二維位置

2.所有邊權都是0或1,因此可以用雙端隊列,保證時間復雜度是線性的。

AcWing 1134. 最短路計數

//求方案數

  1. 先求出全局最小值是多少
  2. 分別求出每個子集中等於全局最小值的元素個數

//最短路樹(拓撲圖)上保證不存在邊權為0的環,否則答案的方案數則為正無窮。

 

//本題用BFSDijkstra做沒有問題,但是不能用spfa

//求方案數時如果有負權邊,則先用spfa求一遍最短路,再循環遍歷每一條邊,若該邊滿足三角不等式,則加入最短路樹中,最后將最短路樹建好,再由拓撲序求最短路樹上的方案數。

AcWing 383. 觀光

//最短路徑的條數

次短路徑:如果存在比最短路徑長度恰好多1的路徑,則再把這樣的路徑條數加上

d[i,0]表示從1到i的最短路徑 cnt[i,0]

d[i,1]表示從1到i的次短路徑 cnt[i,1]

Floyd算法(兼具DP和圖論的性質

1.多源多匯最短路:可在的時間復雜度之內求出任意兩點間的最短路

2.傳遞閉包:將所有可以間接到達的點連上直接到達的邊

如果存在i->j這條邊,則g[i,j]=1

如果不存在i->j這條邊,則

(1) 初始化:d[i,j]=g[i,j]

(2) for(k)

for(i)

for(j)

if(d[i,k]&&d[k,j])

d[i,j]=1;

3.找最小環

4.恰好經過k條邊的最短路(倍增思想)

//Floyd和Bellman-Ford、spfa算法都是基於DP

  Dijkstra基於貪心

//動態規划

一、狀態表示

d[k,i,j]表示從i到j只經過1~k的話,最短路徑是多少

1.集合:所有從i出發,最終走到j,且中間只經過節點編號不超過k的所有路徑。

2.屬性:路徑長度的最小值

二、狀態計算

1.所有不含節點k的路徑

最小值為d[k-1,i,j]

2.所有包含節點k的路徑

最小值為d[k-1,i,k]+d[k-1,k,j]

 

去掉第一維后:

下面來證明循環當中是否可以去掉第一維:

特殊情況:當k=j時,

由於經過預處理,d(k,k)=0,所以d(i,k)=d(i,k)。說明在循環一輪后,d(k,i,k)仍然等於d(k-1,i,k)。同理得d(k,k,j)=d(k-1,k,j)。所以在循環中可以去掉第一維。

AcWing 1125. 牛的旅行

//牧區:節點

  牧場:連通塊

//具體思路:

(1) 用floyd算法求出任意兩點之間的最短距離

(2) 求maxd[i],表示和i連通的且距離i最遠的點的距離

(3) 情況1:答案為所有maxd[i]的最大值

情況2:枚舉在哪兩個點之間連邊,需要滿足d[i,j]=INF。答案為

//本題數據較大,INF最好定義為1e20

AcWing 343. 排序

//假定如果A<B,則d(A,B)=1

1.矛盾:d(i,i)=1

2.唯一確定:當i≠j時,d(i,j)、d(j,i)中必有一個是1

3.順序不唯一

//改良 將變成

 

AcWing 344. 觀光之旅

//集合:按照環上編號最大的點分類

如果d(i,j)=d(i,k)+d(k,j),則k為i->j中編號最大的點

AcWing 345. 牛站

//d[k,i,j]表示從i到j,恰好經過k條邊的最短路徑

 

(本題中可以存在負環)

//滿足結合律,那么就可以用倍增(快速冪)的思想處理這道。由d(2,i,j)得到d(4,i,j),再得到d(8,i,j)

  因此時間復雜度可優化為

//因為實際用到的點數遠小於總的點數,所以可以把點的編號離散化一遍,降低時間復雜度。

最小生成樹(無向邊)

 

當前與外界直接相連的權值最小的一條邊。這條邊一定可以出現在最優解中。

如何證明當前這條邊一定可以被選?

假設不選當前邊,最終得到了一棵樹。然后將這條邊加上,那么必然會出現一個環,在這個環上,一定可以找出一條長度不小於當前邊的邊,那么把當前邊替換上去,結果一定不會變差。

AcWing 1140. 最短網絡

AcWing 1141. 局域網

//相當於在這個圖的每個連通塊內,求一棵最小生成樹。相當於求原圖的“最小生成森林”。

//做Kruskal算法

  1. 將所有邊權從小到大排序
  2. 依次枚舉每條邊a,b,w

如果a和b不連通,那么就將當前邊加到最小生成樹中去。

//可以用Prim算法時一定可以用Kruskal算法,但用Kruskal算法時不一定可以用Prim算法(例如本題)

AcWing 1142. 繁忙的都市

//普通的最小生成樹:所有的邊權之和最小

本題中的最小生成樹:最大的邊權最小

//做法:Kruskal

  1. 將所有邊從小到大排序
  2. 從小到大依次枚舉每條邊,a,b,w

如果a和b已經連通,那么直接pass

如果a和b不連通,那么就將當前邊選出來

AcWing 1143. 聯絡員

//讀題->分析模型->算法->代碼

1.將所有必選邊加到並查集中

2.將所有非必選邊從小到大排序

3.從小到大依次枚舉每一條非必選邊,a,b,w

如果a和b已經連通,直接pass

如果a和b不連通,那么就將當前邊選上

//Kruskal算法:可以只實現前一半,也可以在已經有邊的前提下繼續做后一半

AcWing 1144. 連接格點

//注意!這不是一個最小生成樹問題:n個點,m條邊,邊權可正可負,求將所有點連通的最小邊權和是多少?

//O(klogk)->O(k)

//將二維變成一維

//容易沖突的變量名:y1,next,prev,hash

//為了省去排序的時間,先將縱向邊(權值為1)加入,再將橫向邊(權值為2)加入

 

最小生成樹的擴展應用

定理

任意一棵最小生成樹一定可以包含無向圖中權值最小的邊

證明:

反證法。假設無向圖G=(V,E)存在一棵最小生成樹不包含權值最小的邊。設e=(x,y,z)是無向圖中權值最小的邊。把e添加到樹中,e會和樹上從x到y的路徑一起構成一個環,並且環上其他邊的權值都比z大。因此,用e代替環上的其他任意一條邊,會形成一棵權值和更小的生成樹,與假設矛盾。故假設不成立,原命題成立。

推論

給定一張無向圖G=(V,E),n=|V|,m=|E|。從E中選出k<n-1條邊構成G的加一個生成森林。若再從剩余的m-k條邊中選n-1-k條添加到生成森林中,使其成為G的生成樹,並且選出的邊的權值之和最小,則該生成樹一定包含這m-k條邊中連接生成森林的兩個不連通節點的權值最小的邊。

//以上來自《算法競賽 進階指南》

AcWing 1146. 新的開始

//建立一個“超級發電站”,將所有礦井與其都連上邊

AcWing 1145. 北極通訊網絡

//找一個最小的d值,使得將所有權值大於d的邊刪去之后,整個圖形的連通塊的個數不超過k。

//Kruskal算法:假設當前已經循環完第i條邊。已經求出了由前i條邊構成的連通塊。

//可以用DFS/BFS+二分,但用並查集的話則無需二分

 

AcWing 346. 走廊潑水節

//對於兩個連通塊:

  1. 新邊<w ×
  2. 新邊==w ×
  3. 新邊≥w+1 

  這樣才能保證圖的唯一最小生成樹仍是原樹。

AcWing 1148. 秘密的牛奶運輸

//次小生成樹

定義:給一個帶權的圖,把圖的所以生成樹按權值從小到大排序,第二小的稱為次小生成樹。

//非嚴格次小生成樹的邊權可以和最小生成樹相等,而嚴格次小生成樹則不可以。

定理:對於一張無向圖,如果存在最小生成樹和(嚴格)次小生成樹,那么對於人格一棵最小生成樹,都存在一棵(嚴格)次小生成樹,使得這兩棵樹只有一條邊不同。

方法1:先求最小生成樹,再枚舉刪去最小生成樹中的邊求解。時間復雜度

方法2:先求最小生成樹,然后依次枚舉非樹邊,然后將該邊加入樹中,同時從樹中去掉一條邊,使得最終的圖仍是一棵樹。則一定可以求出次小生成樹。

  1. 設T為圖G的一棵生成樹,對於非樹邊a和樹邊b,插入邊a,並刪除邊b的操作記為(+a,-b)
  2. 如果T+a-b之后,仍然是一棵生成樹,稱(+a,-b)是T的一個可行交換。
  3. 稱由T進行一次可行變換所得到的新的生成樹集合為T的鄰集

定理:次小生成樹一定在最小生成樹的鄰集中。

//以上來自《信息學奧賽一本通·提高篇》

要使得最小,就要使最大。可以枚舉n個點,以每一個點為樹根,復雜度預處理出每個點到其他所有點的路徑上的最大邊權。所以時間復雜

 

//也可以用樹鏈剖分進行預處理

1.求最小生成樹,標記每條邊是樹邊,還是非樹邊;同時把最小生成樹建立出來。

2.預處理任意兩點間的邊權最大值dist[a][b]

3.依次枚舉所有非樹邊,求,滿足w>dist[a][b]。

//注意:在求嚴格次小生成樹時,不能只預處理兩點之間最大的樹邊,因為當最大樹邊和當前枚舉的非樹邊長度相同時,就不能替換了,但此時卻可以替換長度次大的樹邊。因此還需同時預處理出長度次大的樹邊。

負環

01分數規划

求負環的常用方法,基於spfa:(基於抽屜原理)

  1. 統計每個店入隊的次數,如果某個點入隊n次,則說明存在負環
  2. 統計當前每個點的最短路中所包含的邊數,如果某點的最短路所包含的邊數大於等於n,則也說明存在環(一般選擇這種方法)

將所有點加入隊列中,並初始化dist[i]=0。此時可以看成由虛擬源點向所有點都連了一條邊,不影響負環的判斷。又因為無論dist數組初始化成0還是0x3f3f3f3f,有負環存在都會逐漸減為負無窮,所以初始化成任意值皆可。也沒必要memset

當所有點的入隊次數超過2n時,我們就認為圖中與很大可能是存在負環的。

AcWing 904. 蟲洞

AcWing 361. 觀光奶牛

//使最大,即01分數規划問題

 ,可用二分

 

  將邊權重定義為,判斷是否存在正環不一定要把邊權取負,可以在spfa中改變判斷符號,變成求最長路。

//保留兩位小數,二分時>1e-4即可

  同理,若保留三位小數,則>1e-5

AcWing 1165. 單詞環

//建圖:

  以每個單詞的前兩個字母和后兩個字母為節點,以單詞的長度為邊,最多建立676個點、10⁵條邊

//同樣還是01分數規划問題,解法同上題

//優化:在循環時計數,當循環次數cnt>2*n(n為點數)時就可以直接認為存在正環。將隊列換成棧也可以。(但在普通題目中無需將隊列換成棧,因為棧的效率極低)

差分約束

(1) 求不等式組的可行解

源點需要滿足的條件:從源點出發,一定可以走到所有的邊。

步驟

  1. 先將每個不等式xi<=xj+c轉化成一條從xj走到xi,長度為ck的一條邊
  2. 找一個超級源點,使得該源點一定可以遍歷到所有邊
  3. 從源點求一遍單源最短路

結果

  1. 如果存在負環,則原不等式組一定無解
  2. 如果沒有負環,則dist[i]就是原不等式組的一個可行解

//最短路:所有從1->i的路徑的最小值

  最長路:所有從1->i的路徑的最大值

(2) 如何求最大值或最小值,這里的最值指的是每個變量的最值

結論

如果求的是最小值,則應該求最長路;如果求的是最大值,則應該求最短路。

以求xi的最大值為例:所有從xi出發,構成的不等式鏈xi<=xj+c1<=xk+c2+c1<=...<=c1+c2+...+ck所計算出的上界,最終xi的最大值等於所有上界的最小值。

同理,若是求最大值,則是求所有下界的最大值。

問題

如何轉化xi<=c,其中c是一個常數,這類的不等式

方法

建立一個超級源點,0,然后建立0->xi,長度是c的邊即可

AcWing 1169. 糖果

//最小值則求最長路

  相對關系:

 

  絕對關系:

 

//無解情況:是否存在正環

//邊數組大小開三倍N(最壞情況下都是A=B,需要建雙向邊,另外每個點都要和超級源點連一條邊)

//優化:如果用隊列會TLE幾個數據點,所以將隊列替換成棧

AcWing 362. 區間

//貪心或差分約束

  首先將所有ai變成ai+1,bi變成bi+1,這樣數據范圍就變成了[1~50001],為了將0騰出來建立超級源點

//最小值則求最長路(dist數組初始化為-0x3f)

//前綴和思想:Si表示1~i中被選出的數的個數。

//注意:

 

AcWing 1170. 排隊布局

//最大值則求最短路

  建立虛擬源點使得,即從虛擬源點向i號點連了一條邊。但在實際操作中無需真的建立出虛擬源點,將所有點都入隊即可。

 

//無解情況:判斷是否存在負環

//由於題目給定的是相對關系,所以可以令X1=0,那么題目所求的Xn-X1就是Xn,只要求出X1到所有點的最短路,如果Xn的值為正無窮,則說明 1 號奶牛和 N 號奶牛間的距離可以任意大,否則1 號奶牛和 N 號奶牛間可能的最大距離即Xn。

//本題需要進行兩次spfa,對於第一問,需將所有點都入隊,即spfa(n);對於第二問,只需求出X1到其他點的最短路,即spfa(1)。 //注意每次spfa前都要初始化:

 

  cnt數組記錄當前路徑的邊數,即用來判斷是否存在負環。

AcWing 393. 雇佣收銀員

//最小值則最長路

//num[i]表示i時刻來的人數

  X[i]表示最終從num[i]中挑出來的人數

,也是為了將0騰出來建立超級源點

 

//前綴和思想:令Si為Xi的前i項和,則

 

 

  由於在最后一個式子中有三個變量,所以我們可以直接從小到大在0~1000內枚舉,如果找到符合條件的就直接輸出,若循環結束仍未找到則說明無解。

//在枚舉的過程中,為了體現是個定值,即

 

 

 

最近公共祖先

  1. 向上標記法 O(n)
  2. 倍增法

fa[i,j]表示從i開始,向上走2^j步所能走到的節點。

depth[i]表示深度

//哨兵:如果從i開始跳2^j步會跳過根節點,那么fa[i,j]=0。   depth[o]=0

//步驟:(二進制拼湊法)

(1) 先將兩個點跳到同一層

(2) 讓兩個點同時往上跳,一直跳到它們的最近公共祖先的下一層。

預處理 O(nlogn) //廣搜,不會爆棧

查詢O(logn)

//j=0,f(i,j)=i的父節點

  j>0,f(i,j)=f(f(i,j-1),j-1)

  1. Tarjan——離線求LCA O(n+m)

//本質上是對向上標記法的優化

在深度優先遍歷時,將所有點分成三大類:

1) 已經遍歷過,且回溯過的點

2) 正在搜索的分支

3) 還未搜索到的點

AcWing 1172. 祖孫詢問

//倍增求lca

AcWing 1171. 距離

//兩點之間的最短距離:d(x)+d(y)-2*d(lca(x,y))

//預處理出每個節點到根節點的距離d(i)

//用vector<PII>來存詢問,first存查詢的另外一個點,second存查詢編號

AcWing 356. 次小生成樹

//注意要用long long,會爆int

//思路和AcWing 1148. 秘密的牛奶運輸相似

//d1[i,j]表示i->j路徑上的最大邊

  d2[i,j]表示i->j路徑上的次大邊

 

 

 

 

AcWing 352. 闇の連鎖

//樹上差分

  給從x到y的路徑上的所有邊都加上c:

  

//最后枚舉每棵子樹:

 

有向圖的強連通分量

對於一個有向圖,連通分量:對於分量重任意兩點u,v,必然可以從u走到v,且從v走到u。

有向圖通過縮點(將所有連通分量縮成一個點)變成有向無環圖(DAG),即拓撲圖,便於求最短(或最長)路、遞推。時間復雜度為O(n+m)。

DFS(樹枝邊、前向邊:指向某個子孫、后向邊:指向某個祖宗、橫叉邊)

情況1:存在后向邊指向祖先節點

情況2:先走到橫叉邊,橫叉邊再走到祖先

Tarjan算法求強連通分量(SCC)

對每個點定義兩個時間戳:

dfn[u]表示遍歷到u的時間戳

low[u]從u開始走,所能遍歷到的最小時間戳是什么。

u是其所在的強連通分量的最高點,等價於dfn[u]==low[u]

//棧中放當前強聯通分量中還沒有搜完的所有點

  1. 縮點

for(i=1;i<=n;i++)

for(i的所有鄰點j)

if(i與j不在同一個SCC中)

加一條新邊 id(i)->id(j)

//連通分量編號遞減的順序一定是拓撲序

AcWing 1174. 受歡迎的牛

//先縮點,再在拓撲圖里找出出度為零的點。(如果有兩個或以上這樣的點,本題答案即為0)答案即這個點所代表的強連通分量中的點數。

AcWing 367. 學校網絡

//設縮點后有P個起點,Q個終點

//第一問即P

//第二問為max(P,Q)

假設|P|≤|Q|

1) |P|==1 ans=|Q|

2) |P|>1 |Q|≥|P|>1

必能找到兩個不同的起點到達不同的終點,設這兩個起點分別為p1、p2,終點分別為q1、q2。

//反證:如果找不到這樣的兩個點,說明所有起點都到達同一個終點q1。但|Q|>|P|,所以必然有q2是來自其中一個起點,得出矛盾。

此時給q1、p2連一條邊,則|P’|=|P|-1,|Q’|=|Q|-1。連|P|-1次這樣的邊,使得|P|=1,那么此時總共連的邊數為|Q|-(|P|-1)+|P|-1,即|Q|。

//第二問注意特判:如果只有一個強連通分量,則答案為0

AcWing 1175. 最大半連通子圖

//導出子圖:從原圖中選出一些點,再把所有跟這些點相關的邊都選出來(如果兩點間有多條邊,則應將這些邊全部選出)。

  1. Tarjan
  2. 縮點(不能有重邊)建圖,給邊判重
  3. 按拓撲序遞推

//第一問:求拓撲圖的最長鏈

//第二問:求最長鏈的方案數 DP

  設f(i)為表示到i這個點的最長鏈的長度,g(i)表示到到i這個點的最長鏈的方案數,s(i)表示i這個強連通分量中的點數。

如果可以從j->i:

1.若f(j)+s(i)>f(i),則f(I)=f(j)+s(i),且g(i)=g(j)

2.若f(j)+s(i)==f(i),則g(i)+=g(j)

//因為連通分量編號遞減的順序一定是拓撲序,所以無需再次建圖,只要按照該順序DP即可。

AcWing 368. 銀河

//本題正解:Tarjan算法(穩定,時間復雜度可達線性)

  1. Tarjan
  2. 縮點
  3. 依據拓撲序遞推

//本題可以用01分數規划,思路類似AcWing 1169. 糖果 ,將隊列換成棧,仍有超時的風險。

 

另外還有兩個條件:

1.必須有絕對值

2.超級源點

 

//本題的特殊性:

邊權都為正,因此在判斷是否存在正環時,只要在某一個強連通分量中有某一條邊的權值大於0,就形成了一個正環(因為強聯通分量中的任意兩點都互相連通)。所以強連通分量中的所有邊的權值都要為0,即所有點最終的距離都相等。因此題目變成了在拓撲圖上,所有點到起點的最長距離。

//建立了超級源點后,就可以直接Tarjan(o)。

//本題需要用long long

無向圖的雙連通分量(也叫重連通分量)

邊雙連通分量e-DCC:極大的不包含橋的連通塊

//:刪去橋原圖不連通

//性質1:不管刪掉哪條邊,該圖仍然連通

  性質2:任意兩點之間都存在兩條不相交的路徑

點雙連通分量v-DCC:極大的不包含割點的連通塊

//割點:刪去割點原圖不連通

//每一個割點都至少屬於兩個連通分量

//兩個割點之間的邊不一定是橋,橋的兩個端點也不一定是割點

  一個點雙連通分量不一定是一個邊雙連通分量,同樣地,一個邊雙連通分量也不一定是一個點雙連通分量

邊雙連通分量:dfn(x)、low(x)

如何找到橋

如何找到所有邊的雙連通分量

  1. 將所有橋刪掉
  2. Stack dfn(x)==low(x)

如何求割點:low(y)≥dfn(i)

(1) 如果x不是根節點,那么x是割點

(2) x是根節點,至少有兩個子節點yi滿足low(yi)≥dfn(i)

如何求點雙連通分量

1) 統計連通塊個數 cnt

2) 枚舉從哪個塊刪,再枚舉刪除哪個點

AcWing 395. 冗余路徑

//兩條路徑沒有一條重合的道路

//給定一個無向連通圖,問最少加幾條邊,可以將其變成一個邊雙連通分量。

//將所有邊雙連通分量縮點,原圖變成了一棵樹,再將所有葉子節點連接起來。(cnt為葉子節點的數量)

AcWing 1183. 電力

//求割點 stack

//多組數據記得memset(dfn,0,sizeof dfn)

//孤立點也是雙聯通分量

 

AcWing 396. 礦場搭建

//給定一個無向圖,問最少在幾個點上設置出口,可以使得不管哪個點坍塌,其余所有點都可以與某個出口連通。

  1. 出口數量≥2
  2. 分別看每個連通塊

1) 無割點 

2) 有割點

  1. 縮點:

1.每個割點單獨作為一個點

2.從每個v-DCC向其所包含的每個割點連邊

  1. V-DCC度數為1:需在該分量內部(非割點)放一個出口
  2. V-DCC度數>1:無需設置出口

歐拉回路和歐拉路徑

哥尼斯堡七橋問題(一筆畫)

  1. 對於無向圖,所有邊都是連通的

(1) 存在歐拉路徑的充分必要條件:度數為奇數的點只能有0或2個。

(2) 存在歐拉回路的充分必要條件:度數為奇數的點只能有0個。

  1. 對於有向圖,所有邊都是連通的

(1) 存在歐拉路徑的充分必要條件:要么所有點的出度均等於入度;要么除了兩個點以外,其余所有點的出度等於入度,剩余的兩個點:一個滿足出度比入度多1(起點),另一個滿足入度比出度多1(終點)。

(2) 存在歐拉回路的充分必要條件:所有點的出度均等於入度。

實現方式:dfs,在dfs的最后將當前遍歷的節點加入隊列中

注意:用邊判重,時間復雜度可能會很高。可以在走過一條邊之后就將這條邊刪去。在無向圖中,由於建了雙向邊,兩條邊都要刪掉。雙向邊的編號為(1,2) (3,4) (5,6)......

AcWing 1123. 鏟雪車

//由於每個點的入度和出度都相等,從起點可以到任意一條街道,顯然本題就是一個歐拉回路。只要將所有街道的長度之和乘2,再除以鏟雪車的速度即可。

//注意答案輸出的單位轉化

//本題乍一看是一道圖論題,但實際上通過分析題目不難得出歐拉回路的結論。

AcWing 1184. 歐拉回路

//如何判斷無解:

  1. 無向圖:

(1) 所有點的度數必須是奇數

(2) 所有邊連通

  1. 有向圖:

(1) 所有點的入度等於出度

(2) 所有邊連通

AcWing 1124. 騎馬修柵欄

//保證dfs中for循環里u的所有出邊都按照從小到大的順序,這樣輸出的答案就會是字典序最小的。

AcWing 1185. 單詞游戲

//以字母為點(26個點),以單詞為邊

判斷有向圖是否存在歐拉路徑

  1. 除了起點和終點外,其余點入度=出度
  2. 所有邊都連通(並查集

拓撲排序

拓撲圖=有向無環圖

將所有入度為0的點入隊

對於任意一個點,其前驅點的個數都是有限的

AcWing 1191. 家譜樹

//每輸入一個孩子,就使孩子的入度++

//拓撲排序模板

AcWing 1192. 獎金

//差分約束求最長路

1) 邊權無限制 spfa O(nm)

2) 邊權非負 tarjan O(n+m)

3) 邊權>0 拓撲排序 O(n+m)

//用拓撲排序來做差分約束問題。每個點都最小,使得總和最小

AcWing 164. 可達性統計

//DP

f(i):所有能從i到達的點的集合

 

集合用長度為n的二進制串表示(例如1011001......),並使用bitset函數

AcWing 456. 車站分級

//暴力建圖會超時

//告訴我們很多個a>b,要求最小的等級,即從b->a建立邊權為1的邊(很裸的查分約束問題)

1.拓撲排序

2.虛擬源點:將n^2的復雜度變成了線性

//若要連接兩個集合,可在集合之間建立一個虛擬源點,從左邊的集合中的每一個點向虛擬源點建立一條邊權為0的邊,再從虛擬源點向右邊集合中的每一個點建立一條邊權為1的邊

 ---------------------------------------------------->

 在最后,感謝Gold_stein(xym)同學提供了自己的筆記供我參考 Thanks♪(・ω・)ノ


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM