【HDU - 2255】奔小康赚大钱(KM算法模板,二分图最优匹配)
題干:
傳說在遙遠(yuǎn)的地方有一個非常富裕的村落,有一天,村長決定進行制度改革:重新分配房子。?
這可是一件大事,關(guān)系到人民的住房問題啊。村里共有n間房間,剛好有n家老百姓,考慮到每家都要有房住(如果有老百姓沒房子住的話,容易引起不安定因素),每家必須分配到一間房子且只能得到一間房子。?
另一方面,村長和另外的村領(lǐng)導(dǎo)希望得到最大的效益,這樣村里的機構(gòu)才會有錢.由于老百姓都比較富裕,他們都能對每一間房子在他們的經(jīng)濟范圍內(nèi)出一定的價格,比如有3間房子,一家老百姓可以對第一間出10萬,對第2間出2萬,對第3間出20萬.(當(dāng)然是在他們的經(jīng)濟范圍內(nèi)).現(xiàn)在這個問題就是村領(lǐng)導(dǎo)怎樣分配房子才能使收入最大.(村民即使有錢購買一間房子但不一定能買到,要看村領(lǐng)導(dǎo)分配的).?
Input
輸入數(shù)據(jù)包含多組測試用例,每組數(shù)據(jù)的第一行輸入n,表示房子的數(shù)量(也是老百姓家的數(shù)量),接下來有n行,每行n個數(shù)表示第i個村名對第j間房出的價格(n<=300)。?
Output
請對每組數(shù)據(jù)輸出最大的收入值,每組的輸出占一行。?
?
Sample Input
2 100 10 15 23Sample Output
123?
解題報告:
? ?裸的KM算法,當(dāng)個模板記吧。有必要的注釋也都在里面了。
//女生在左側(cè)(x),男生是右側(cè)(y) #include <iostream> #include <cstring> #include <cstdio>using namespace std; const int MAXN = 305; const int INF = 0x3f3f3f3f; int line[MAXN][MAXN]; // 記錄每個妹子和每個男生的好感度 int ex[MAXN],ey[MAXN]; //當(dāng)前的期望最大值 bool visx[MAXN]; // 記錄每一輪匹配匹配過的女生 bool visy[MAXN]; // 記錄每一輪匹配匹配過的男生 int nxt[MAXN]; int slack[MAXN]; // 記錄每個漢子如果能被妹子傾心最少還需要多少期望值 int N; bool dfs(int x) {visx[x] = 1;for (int y = 1; y <= N; ++y) {if (visy[y]) continue; // 每一輪匹配 每個男生只嘗試一次int tmp = ex[x] + ey[y] - line[x][y];if (tmp == 0) { // 如果符合要求visy[y] = 1;if (nxt[y] == -1 || dfs( nxt[y] )) {nxt[y] = x;return 1;}} else if(slack[y] > tmp) slack[y] = tmp;}return 0; } int KM() {memset(nxt, -1, sizeof nxt); // 初始每個男生都沒有匹配的女生memset(ey, 0, sizeof ey); // 初始每個男生的期望值為0// 每個女生的初始期望值是與她相連的男生最大的好感度for (int i = 1; i <= N; ++i) {ex[i] = line[i][1];for (int j = 2; j <= N; ++j) {ex[i] = max(ex[i], line[i][j]);}}// 嘗試為每一個女生解決歸宿問題for (int i = 1; i <= N; ++i) {fill(slack, slack + N + 1, INF); // 因為要取最小值 初始化為無窮大while (1) {// 為每個女生解決歸宿問題的方法是 :如果找不到就降低期望值,直到找到為止memset(visx, 0, sizeof visx);// 記錄每輪匹配中男生女生是否被嘗試匹配過memset(visy, 0, sizeof visy);if (dfs(i)) break;int d = INF;for (int j = 1; j <= N; ++j)if (!visy[j]) d = min(d, slack[j]);for (int j = 1; j <= N; ++j) {if (visx[j]) ex[j] -= d;if (visy[j]) ey[j] += d;/*else*/ slack[j] -= d;// 沒有訪問過的boy 因為girl們的期望值降低,距離得到女生傾心又進了一步!這里的else經(jīng)測試加不加都可以}}}// 匹配完成 求出所有配對的好感度的和int res = 0;for (int i = 1; i <= N; ++i)res += line[ nxt[i] ][i];return res; } int main() {while (~scanf("%d",&N)) {for (int i = 1; i <= N; ++i)for (int j = 1; j <= N; ++j)scanf("%d", &line[i][j]);printf("%d\n", KM());}return 0; }總結(jié):
? ? 可以理解代碼了但是自己寫出來有點吃力。。。。
總結(jié)
以上是生活随笔為你收集整理的【HDU - 2255】奔小康赚大钱(KM算法模板,二分图最优匹配)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 油价上涨挡都挡不住了,本周五,国内油价
- 下一篇: 银行存款利率纷纷上涨,手上有20万,怎么