日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

奔小康赚大钱 HDU - 2255( 二分图匹配KM算法详解)

發布時間:2023/12/4 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 奔小康赚大钱 HDU - 2255( 二分图匹配KM算法详解) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目

傳說在遙遠的地方有一個非常富裕的村落,有一天,村長決定進行制度改革:重新分配房子。?
這可是一件大事,關系到人民的住房問題啊。村里共有n間房間,剛好有n家老百姓,考慮到每家都要有房住(如果有老百姓沒房子住的話,容易引起不安定因素),每家必須分配到一間房子且只能得到一間房子。?
另一方面,村長和另外的村領導希望得到最大的效益,這樣村里的機構才會有錢.由于老百姓都比較富裕,他們都能對每一間房子在他們的經濟范圍內出一定的價格,比如有3間房子,一家老百姓可以對第一間出10萬,對第2間出2萬,對第3間出20萬.(當然是在他們的經濟范圍內).現在這個問題就是村領導怎樣分配房子才能使收入最大.(村民即使有錢購買一間房子但不一定能買到,要看村領導分配的).?

Input

輸入數據包含多組測試用例,每組數據的第一行輸入n,表示房子的數量(也是老百姓家的數量),接下來有n行,每行n個數表示第i個村名對第j間房出的價格(n<=300)。?

Output

請對每組數據輸出最大的收入值,每組的輸出占一行。?
?

Sample Input

2 100 10 15 23

Sample Output

123

分析:

KM模板,具體講解如下:

AC代碼:

#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int inf=0x3f3f3f3f; const int M=330; int mp[M][M]; int s[M]; int a[M],b[M]; int u[M],v[M]; int n,ans; int dp[M]; int x,y; int dfs(int o) {u[o]=1;for(int g=1;g<=y;g++){if(v[g])continue;int tmp=a[o]+b[g]-mp[o][g];if(tmp==0){v[g]=1;if(dp[g]==-1||dfs(dp[g])){dp[g]=o;return 1;}}else if(s[g]>tmp)s[g]=tmp;}return 0; } void KM() {memset(a,0,sizeof(a));memset(b,0,sizeof(b));for(int i=1;i<=x;i++)for(int j=1;j<=y;j++)a[i]=max(a[i],mp[i][j]);for(int k=1;k<=x;k++){for(int i=1;i<=y;i++)s[i]=inf;while(1){memset(u,0,sizeof(u));memset(v,0,sizeof(v));if(dfs(k)) break;int num=inf;for(int i=1;i<=y;i++)if(!v[i]&&num>s[i])num=s[i];for(int i=1;i<=x;i++)if(u[i])a[i]-=num;for(int i=1;i<=y;i++){if(v[i])b[i]+=num;else s[i]-=num;}}} } int main() {while(~scanf("%d",&n)){ans=0;x=y=n;memset(dp,-1,sizeof(dp));for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&mp[i][j]);KM();for(int i=1;i<=y;i++)ans+=mp[dp[i]][i];printf("%d\n",ans);}return 0; }

筆者刷數模題的時候有一道題考到了“二分圖最大權分配”,需要用到KM算法,但是書上對KM算法的介紹又臭又長,更何況有些同學“匈牙利算法”也沒學過(由匈牙利數學家Edmonds提出),自然難以理解所謂的KM算法。本文旨在用通俗易懂的語言,向讀者介紹匈牙利算法和KM算法。

?

一、匈牙利算法

匈牙利算法用于解決什么問題?

匈牙利算法用于解決二分圖的最大匹配問題。

什么是二分圖?我們不妨來考慮這樣一個問題,在一家公司里,有員工A,B,C,有三種工作a,b,c,如果員工和工作之間有線相連,則代表員工能勝任這份工作。

如圖所示,員工A能勝任a,c工作,員工B能勝任a,b,c工作,而員工C只能勝任c工作。

上圖就是所謂的“二分圖”(請忽略圖中箭頭),簡單的說,上圖可劃分為兩個集合{員工},{工作},兩個集合之間的元素可以相連,同一個集合內的元素不能相連。

下面請解決這樣一個問題:請給出一個方案,讓盡可能多的員工有不同的工作做。“匈牙利算法”的出現就是為了解決這個問題。

下面給出這個問題的解決方案:(讀者看到這里可能會想,解決這個問題不是很簡單嗎?A→a,B→b,C→c不就好了?請注意:任何算法的給出都是為了規整化一個問題的解決步驟,其目的是為了在問題規模越來越大時算法對其仍然適用,如果公司有10個員工或者更多,讀者想必不能一眼看出答案,此時,算法的作用便體現出來了。)

我們先幫A找工作做,不妨先幫A連上a(紅線表示此時兩者已經匹配),表示A去做a工作。

??

接下來我們幫B找工作做,B的第一條線跟a相連,B也想做工作a。

這時候就發生了沖突(collision),如何解決呢?

匈牙利算法”指出 通過一條增廣路徑,通過取反操作,我們就能匹配更多的點。

什么是增廣路徑?增廣路徑是指,由一個未匹配的頂點開始,經過若干個匹配頂點,最后到達對面集合的一個未匹配頂點的路徑,即這條路徑將兩個不同集合的兩個未匹配頂點通過一系列匹配頂點相連。

比如此題中,B想做工作a,于是A想著換一個工作,我們連上A,c。

?

如圖,B→a→A→c 其中B,c未匹配,A,a已匹配,按照定義,這就是一條增廣路徑,我們對其進行取反操作,就變成了下圖。

?

取反操作為我們帶來了什么?原本只有一邊匹配,現在有兩邊匹配了,而且沖突也解決了,這就是匈牙利算法的妙處,我們能通過不停的尋找這樣一條增廣路徑,從而找到二分圖的最大匹配

下面我們繼續尋找增廣路徑。

最終,我們得到了一個最大匹配:A匹配a,B匹配b,C匹配c,就算集合中的元素很多很多,我們仍能通過匈牙利算法得到該二分圖的最大匹配。

二、KM算法


現在我們來考慮另外一個問題:如果每個員工做每件工作的效率各不相同,我們如何得到一個最優匹配使得整個公司的工作效率最大呢?

這種問題被稱為帶權二分圖的最優匹配問題,可由KM算法解決。

比如上圖,A做工作a的效率為3,做工作c的效率為4......以此類推。

不了解KM算法的人如何解決這個問題?我們只需要用匈牙利算法找到所有的最大匹配,比較每個最大匹配的權重,再選出最大權重的最優匹配即可。這不失為一個解決方案,但是,如果公司員工的數量越來越多,此種算法的實行難度也就越來越大,我們必須另辟蹊徑:KM算法。

KM算法解決此題的步驟如下所示:

1.首先對每個頂點賦值,將左邊的頂點賦值為最大權重,右邊的頂點賦值為0。

如圖,我們將頂點A賦值為其兩邊中較大的4。

2.進行匹配,我們匹配的原則是:只與權重相同的邊匹配,若是找不到邊匹配,對此條路徑的所有左邊頂點-1,右邊頂點+1,再進行匹配,若還是匹配不到,重復+1和-1操作。(這里看不懂可以跳過,直接看下面的操作,之后再回頭來看這里。)

對A進行匹配,符合匹配條件的邊只有Ac邊。

匹配成功!

接下來我們對B進行匹配,頂點B值為3,Bc邊權重為3,匹配成~ 等等,A已經匹配c了,發生了沖突,怎么辦?我們這時候第一時間應該想到的是,讓B換個工作,但根據匹配原則,只有Bc邊 3+0=0 滿足要求,于是B不能換邊了,那A能不能換邊呢?對A來說,也是只有Ac邊滿足4+0=4的要求,于是A也不能換邊,走投無路了,怎么辦?

從常識的角度思考:其實我們尋找最優匹配的過程,也就是幫每個員工找到他們工作效率最高的工作,但是,有些工作會沖突,比如現在,B員工和A員工工作c的效率都是最高,這時我們應該讓A或者B換一份工作,但是這時候換工作的話我們只能換到降低總體效率值的工作,也就是說,如果令R=左邊頂點所有值相加,若發生了沖突,則最終工作效率一定小于R,但是,我們現在只要求最優匹配,所以,如果A換一份工作降低的工作效率比較少的話,我們是能接受的(對B同樣如此)。

在KM算法中如何體現呢?

現在參與到這個沖突的頂點是A,B和c,令所有左邊頂點值-1,右邊頂點值+1,即 A-1,B-1. c+1,結果如下圖所示。

我們進行了上述操作后會發現,若是左邊有n個頂點參與運算,則右邊就有n-1個頂點參與運算,整體效率值下降了1*(n-(n-1))=1,而對于A來說,Ac本來為可匹配的邊,現在仍為可匹配邊(3+1=4),對于B來說,Bc本來為可匹配的邊,現在仍為可匹配的邊(2+1=3),我們通過上述操作,為A增加了一條可匹配的邊Aa,為B增加了一條可匹配的邊Ba。

現在我們再來匹配,對B來說,Ba邊 2+0=2,滿足條件,所以B換邊,a現在為未匹配狀態,Ba匹配!

我們現在匹配最后一條邊C,Cc 5+1!=5,C邊無邊能匹配,所以C-1。

現在Cc邊 4+1=5,可以匹配,但是c已匹配了,發生沖突,C此時不能換邊,于是便去找A,對于A來說,Aa此時也為可匹配邊,但是a已匹配,A又去找B。

??

B現在無邊可以匹配了,2+0!=1 ,現在的路徑是C→c→A→a→B,所以A-1,B-1,C-1,a+1,c+1。如下圖所示。

對于B來說,現在Bb 1+0=1 可匹配!

使用匈牙利算法,對此條路徑上的邊取反。

如圖,便完成了此題的最優匹配。

讀者可以發現,這題中沖突一共發生了3次,所以我們一共降低了3次效率值,但是我們每次降低的效率值都是最少的,所以我們完成的仍然是最優匹配

這就是KM算法的整個過程,整體思路就是:每次都幫一個頂點匹配最大權重邊,利用匈牙利算法完成最大匹配,最終我們完成的就是最優匹配

總結

以上是生活随笔為你收集整理的奔小康赚大钱 HDU - 2255( 二分图匹配KM算法详解)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。