poj 3020 最小邊覆蓋與最大匹配 匈牙利演算法

2021-06-23 01:23:17 字數 2807 閱讀 3875

做了一些題之後感覺自己的知識儲備真的太少了,很多東西都不知道;

題目大意:

乙個矩形中,有n個城市』*』,現在這n個城市都要覆蓋無線,若放置乙個基站,那麼它至多可以覆蓋相鄰的兩個城市。

問至少放置多少個基站才能使得所有的城市都覆蓋無線?

解題思路:

思前想後,依稀可以認為是一道求二分圖的最小路徑覆蓋問題

(注意不是最小點覆蓋)

那麼接下來需要確認的是,

究竟是求 有向二分圖的最小路覆蓋,還是求 無向二分圖的最小路覆蓋

因為有向和無向是截然不同的計算方法。

要確認是構造有向圖,還是構造無向圖,那麼就需要先根據題意,看看構造二分圖時所使用的方式,更適合構造哪一種二分圖。

然後就進入了本題難點:如何構造二分圖

首先要明確的是,輸入的一堆「圈圈星星」可以看做是一張大地圖,地圖上有所有城市的座標,但是這裡有乙個誤區:不能簡單地把城市的兩個x、y座標作為準備構造的二分圖的兩個頂點集。

城市才是要構造的二分圖的頂點!

構造方法如下:

例如輸入:

*oo***

o*o時,可以抽象為乙個數字地圖:

100234

050數字就是根據輸入的城市次序作為該城市的編號,0代表該位置沒有城市。

然後根據題目的「範圍」規則,從第乙個城市開始,以自身作為中心城市,向四個方向的城市進行連線(覆蓋)

因此就能夠得到邊集:

e12  e21     e32     e43    e53

e23     e34

e35可以看到,這些邊都是有向邊,但是每一條邊都有與其對應的一條相反邊。

即任意兩個城市(頂點)之間的邊是成對出現的

那麼我們就可以確定下來,應該 構造無向二分圖(其實無向=雙向)

因為若要構造有向的二分圖時,需要判斷已出現的邊,是很麻煩的工作

為了把有向圖g構造為無向二分圖,這裡需要引入乙個新名詞「拆點」

其實就是把原有向圖g的每乙個頂點都」拆分(我認為複製更準確)」為2個點,分別屬於所要構造的二分圖的兩個頂點集

例如在剛才的例子中抽出一條有向邊e12舉例說明:

複製頂點1和頂點2,使得1,2∈v1;  1』,2』∈v2 ,不難發現|v1|=|v2|

根據邊e12和e21,得到無向二分圖:

那麼同理就可以得到剛才的例子的 無向二分圖為:

再繼而通過無向二分圖,以v1的元素作為row,v2的元素作為col,構造 可達矩陣 儲存到計算機

1』  2』  3』  4』  5』

1  f  t   f   f   f

2  t  f   t   f   f

3  f  t   f   t   t

4  f  f   t   f   f

5  f  f   t   f   f

接下來就是要求這個 無向二分圖的最小路徑覆蓋 了

利用公式:

無向二分圖的最小路徑覆蓋 = 頂點數 – 最大二分匹配數/2

頂點數:就是用於構造無向二分圖的城市數,即進行「拆點」操作前的頂點數量

最大二分匹配書之所以要除以2,是因為進行了「拆點」擦奧做做使得匹配總數多了一倍,因此除以2得到原圖的真正的匹配數

最後剩下的問題就是求最大二分匹配數了,用匈牙利演算法,這就不多說了,參考poj3041的做法,基本一摸一樣。

從這道題得出了乙個結論:

當二分圖的兩個頂點子集基數相等時,該二分圖所有頂點的匹配數 等於 任意乙個頂點子集匹配數的2倍 

其實匈牙利演算法解題是極為簡單的,但是圖論的難並不是難在解答,而是建圖的過程,也難怪會有牛曰:用匈牙利演算法,建圖是痛苦的,最後是快樂的。

//memory time 

//420k 16ms

#includeusing namespace std;

int ipmap[41][11]; //標記存在城市'*'的位置,並依次記錄城市的編號

int ip; //城市編號(最終是城市數量)

int v1,v2; //二分圖的兩個頂點集

int m; //最大二分匹配

bool city[401][401]; //標記兩個城市之間是否能連通

//通過「拆點」操作,把每乙個城市拆分為2個,分別屬於所構造的二分圖的兩個點集

bool vist[401];

int link[401];

int dire_r[4]=;

int dire_c[4]=; //分別對應四個方位 上 下 左 右

/*hungary algorithm*/

bool dfs(int x)

} return false;

}void search(void)

return;

}int main(void)

/*structure the bipartite graphs*/

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

for(j=1;j<=w;j++)

if(ipmap[i][j])

for(int k=0;k<4;k++)

//二分圖構造完畢後,之後的問題就和poj3041一樣處理了

v1=v2=ip;

/*增廣軌搜尋*/

search();

/*output*/

cout<

} return 0;

}

樹上最小邊覆蓋問題

1077.皇宮看守 對於一條邊,可以由父節點覆蓋,或者子節點覆蓋,f u 0 表示該節點不放士兵,f u 1 表示該節點放士兵.當該節點不放時,只有由所有子節點放的情況轉移 當該節點放時,可以由子節點放或不放的情況轉移而來 includeusing namespace std const int n...

POJ 3020(最小路徑覆蓋 拆點)

題意 乙個矩形中,有n個城市 現在這n個城市都要覆蓋無線,若放置乙個基站,那麼它至多可以覆蓋相鄰的兩個城市。問至少放置多少個基站才能使得所有的城市都覆蓋無線?思路 每個城市才是要構造的二分圖的頂點,先把每個 用數字1 n標記起來,然後構造無向二分圖,無向二分圖的構造需要拆點,即12之間的雙向邊要拆成...

HDU 1350 最小邊覆蓋

將某個人的行程視為二分圖中的乙個節點,用結構體記錄每個節點的資訊 起點時間,終點時間,位置 然後對於每個節點,看它結束後能否提前趕到其他節點,能的話就加邊。然後就用二分圖匹配,算出最小邊覆蓋就可以了。為什麼是最小邊覆蓋,因為乙個計程車走一條邊,囊括所有節點的最少的邊數就是我們要求的最少計程車數。記得...