http://acm.hdu.edu.cn/showproblem.php?pid=2255
奔小康賺大錢
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 17692 Accepted Submission(s): 7450
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
Source
HDOJ 2008 Summer Exercise(4)- Buffet Dinner
Recommend
lcy
二分圖最大權分配板子,關於二分圖的講解在另一篇博客(未完成)。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=310;
int n,v[N][N],exa[N],exb[N];//v存邊權,exa是a的點權,exb是b的點權
int con[N];//存b匹配的a(而不是a匹配的b,在給a配對時,是判斷b是否已經被匹配)
bool visa[N],visb[N];//增廣路中的a,b
int slack[N];//每次減去的d
bool dfs(int a)
{
visa[a]=1;
for(int b=1;b<=n;b++)
{
if(visb[b])
continue;
int gap=exa[a]+exb[b]-v[a][b];
if(gap==0)
{
visb[b]=1;
if(!con[b]||dfs(con[b]))
{
con[b]=a;
return true;
}
}
else
slack[b]=min(slack[b],gap);
}
return false;
}
int km()
{
mem(con,0);
for(int i=1;i<=n;i++)
{
mem(slack,INF);
while(1)
{
mem(visa,0);
mem(visb,0);
if(dfs(i))
break;
int d=INF;
for(int j=1;j<=n;j++)
if(!visb[j])
d=min(d,slack[j]);
for(int j=1;j<=n;j++)
{
if(visa[j])
exa[j]-=d;
if(visb[j])
exb[j]+=d;
else
slack[j]-=d;
}
}
}
int res=0;
for(int i=1;i<=n;i++)
res+=v[con[i]][i];
return res;
}
int main()
{
while(~scanf("%d",&n))
{
mem(v,0);
mem(exa,0);
mem(exb,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&v[i][j]);
exa[i]=max(exa[i],v[i][j]);
}
printf("%d\n",km());
}
}