1. 程式人生 > >HDU 2255 奔小康賺大錢 (KM演算法+二分圖最大權匹配)

HDU 2255 奔小康賺大錢 (KM演算法+二分圖最大權匹配)

奔小康賺大錢

Time Limit: 1000/1000 MS (Java/Others)   
Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8774    
Accepted Submission(s): 3871

Problem Description

    傳說在遙遠的地方有一個非常富裕的村落,有一天,村長決定進行制度改革:重新分配房子。
    這可是一件大事,關係到人民的住房問題啊。村裡共有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

題意:給n個農民分n個房子,每個農民對n個房子都有一個期望的價格,
問在每個農民能夠分到房子的情況下,農民支付金錢的總數最大。

KM演算法模板;

AC程式碼:

#include<stdio.h>
#include<string.h> int INF = 0x3f3f3f3f; int n; int ex_people[305],ex_house[305]; ///農民和房子的期望 int link[305][305]; ///農民和房子之間的聯絡 int slack[305]; ///房子被買需要的最小期望 int vis_people[305],vis_house[305]; ///標記農民和房子是否被訪問 int belong[305]; ///記錄房子被哪個農民買 int min(int a,int b){ return a<b?a:b; } int max(int a,int
b){ return a>b?a:b; } int dfs(int p_id){ ///給第p_id個農民找房子 vis_people[p_id]=1; int i; for(i=0;i<n;i++){ if(!vis_house[i]){ int gap=ex_house[i]+ex_people[p_id]-link[p_id][i]; ///計算房子被買需要的期望 if(gap==0){ ///符合要求 vis_house[i]=1; if(belong[i]==-1 || dfs(belong[i])){ ///如果當前房子沒被買 ,或買第i個房子的農民可以買其他房子 belong[i]=p_id; ///讓第p_id個農民買第i個房子 return 1; } } else{ slack[i]=min(slack[i],gap); ///求第i個房子被買需要的最小期望 } } } return 0; } int KM(){ int i,j; for(j=0;j<n;j++) belong[j]=-1; memset(ex_house,0,sizeof(ex_house)); ///將房子期望初始化為0 for(i=0;i<n;i++){ ///初始化農民的期望(能出的最大簽署) ex_people[i]=link[i][0]; for(j=1;j<n;j++) ex_people[i]=max(ex_people[i],link[i][j]); } for(i=0;i<n;i++){ ///給每個農民找房子 for(j=0;j<n;j++) slack[j]=INF; while(1){ memset(vis_house,0,sizeof(vis_house)); memset(vis_people,0,sizeof(vis_people)); if(dfs(i)) ///如果匹配成功 break; int ex=INF; for(j=0;j<n;j++) ///最小可降低的期望值 if(!vis_house[j]) ex=min(ex,slack[j]); for(j=0;j<n;j++){ if(vis_people[j]) ///所有訪問過的農民的期望降低 ex_people[j]-=ex; if(vis_house[j]) ///所有訪問過的房子的期望增加 ex_house[j]+=ex; else slack[j]-=ex; } } } int sum=0; for(i=0;i<n;i++) sum+=link[belong[i]][i]; ///求匹配完成農民負的錢總和 return sum; } int main(){ int i,j; while(~scanf("%d",&n)){ for(i=0;i<n;i++) for(j=0;j<n;j++) scanf("%d",&link[i][j]); printf("%d\n",KM()); } return 0; }