POJ 3041 匈牙利演算法 最小覆蓋 最大二分匹配

來源:互聯網
上載者:User

題目在這裡 http://poj.org/problem?id=3041

因為最近在準備找工作,所以一直在學習演算法,不過我覺得對於一個初學者來說,最難的不是弄懂一個演算法,二是如何將題目編程演算法的模型,然後編寫出程式。個人覺得這個過程應該就是靠多做題,多分析吧,培養自己的靈感來源。

這個題目大概的意思是說, 在一個N*N的矩陣中,有若干個隕石,飛船的大炮可以每次消滅一排或者一列,問如何使得開炮的次數最小,但是卻可以消滅掉所有的隕石。

題目分析:

可以將行和列做如下轉換:

上面的圖中,左圖表示行編號,右圖表示列編號,如果在(i,j)上有一顆隕石,我們將行i 和 列 j串連。

這樣每一條邊都表示一個隕石,如果我在第1行開炮,那麼和行1相連的所有邊就消除了。 所以這樣這個問題就轉換成了最小覆蓋問題。

引入點理論吧,在二分圖中:

匹配:

給定一個二分圖,在G的一個子圖G’中,如果G’的邊集中的任意兩條邊都不依附於同一個頂點,則稱G’的邊集為G的一個匹配

最大匹配:

在所有的匹配中,邊數最多的那個匹配就是二分圖的最大匹配了

頂點覆蓋:

在頂點集合中,選取一部分頂點,這些頂點能夠把所有的邊都覆蓋了。這些點就是頂點覆蓋集

最小頂點覆蓋:

在所有的頂點覆蓋集中,頂點數最小的那個叫最小頂點集合。

二分圖最大匹配的König定理

最大匹配 = 最小頂點覆蓋。此處不證明其正確性。


然後我們寫出程式如下:

#include <stdio.h>#include <memory.h>#define GRID_NUM 505int Grid[GRID_NUM][GRID_NUM];int matched[GRID_NUM];bool visited[GRID_NUM];int nGrid;bool dfs(int from){int i;for( i = 0;i < nGrid; i++){if(!visited[i] && Grid[from][i]){visited[i] = true;if(matched[i] == -1 || dfs(matched[i])){matched[i] = from;return true;}}}return false;}int main(){int nAstroid, j;int f, t;while(scanf("%d%d", &nGrid, &nAstroid) != EOF){memset(Grid, 0, sizeof(Grid));memset(matched, -1, sizeof(matched));for(j = 0; j < nAstroid; j++){scanf("%d%d", &f, &t);Grid[f-1][t-1] = 1;}int nIncrement = 0;for( j = 0; j < nGrid; j++){memset(visited, 0, sizeof(visited));if(dfs(j)){nIncrement++;}}printf("%d\n", nIncrement);}return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.