奔小康赚大钱
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 893 Accepted Submission(s): 412
Problem Description
传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。
另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).
这可是一件大事,关系到人民的住房问题啊。村里共有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
代码:
View Code
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 using namespace std; 6 #define N 310 7 #define MAX 9999999 8 int map[N][N]; 9 bool visitx[N],visity[N]; 10 int lx[N],ly[N]; 11 int match[N]; // match[i] 表示 x集合中与y集合中的i所匹配的点 12 int n; 13 14 bool Hungary(int u) //匈牙利算法 15 { 16 int i,j,k; 17 visitx[u]=true; 18 for(i=0;i<n;i++) 19 { 20 if(!visity[i] && lx[u]+ly[i]==map[u][i]) 21 { 22 visity[i]=true; 23 if(match[i]==-1 || Hungary(match[i])) 24 { 25 match[i]=u; 26 return true; 27 } 28 } 29 } 30 return false; 31 } 32 33 void KM() //KM算法 O(n4) 34 { 35 int temp,i,j,k; 36 memset(lx,0,sizeof(lx)); //初始化顶标 37 memset(ly,0,sizeof(ly)); //ly[i]顶标为0 38 for(i=0;i<n;i++) 39 for(j=0;j<n;j++) 40 lx[i]=max(lx[i],map[i][j]); //lx[i]为全职最大边 41 for(i=0;i<n;i++) 42 { 43 while(1) 44 { 45 memset(visitx,false,sizeof(visitx)); 46 memset(visity,false,sizeof(visity)); 47 if(Hungary(i)) //如果匹配成功 48 break; 49 else //匹配失败 50 { 51 temp=MAX; 52 for(j=0;j<n;j++) //x在交错树中 53 if(visitx[j]) 54 for(k=0;k<n;k++) //y在交错树外 55 if(!visity[k] && temp>lx[j]+ly[k]-map[j][k]) 56 temp=lx[j]+ly[k]-map[j][k]; 57 for(j=0;j<n;j++) //更新顶标 58 { 59 if(visitx[j]) 60 lx[j]-=temp; 61 if(visity[j]) 62 ly[j]+=temp; 63 } 64 } 65 } 66 } 67 } 68 69 int main() 70 { 71 int ans; 72 while(scanf("%d",&n)!=EOF) 73 { 74 ans=0; 75 memset(match,-1,sizeof(match)); 76 for(int i=0;i<n;i++) 77 for(int j=0;j<n;j++) 78 scanf("%d",&map[i][j]); 79 KM(); 80 for(int i=0;i<n;i++) 81 ans+=map[match[i]][i]; 82 printf("%d\n",ans); 83 } 84 return 0; 85 }
附优化版本:
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<climits> 5 #include<algorithm> 6 using namespace std; 7 #define N 310 8 int map[N][N]; 9 bool visitx[N], visity[N]; 10 int lx[N], ly[N]; 11 int slack[N]; 12 int match[N]; 13 int n; 14 15 16 bool Hungary(int u) //匈牙利算法 17 { 18 visitx[u] = true; 19 for(int i = 0; i < n; ++i) 20 { 21 if(visity[i]) 22 continue; 23 if(lx[u] + ly[i] == map[u][i]) 24 { 25 visity[i] = true; 26 if(match[i] == -1 || Hungary(match[i])) 27 { 28 match[i] = u; 29 return true; 30 } 31 } 32 else //不在相等子图 33 slack[i] = min(slack[i], lx[u] + ly[i] - map[u][i]); 34 } 35 return false; 36 } 37 38 void KM_perfect_match() 39 { 40 int temp; 41 memset(lx, 0, sizeof(lx)); //初始化顶标 42 memset(ly, 0, sizeof(ly)); //ly[i]为0 43 for(int i = 0; i < n; ++i) //lx[i]为权值最大的边 44 for(int j = 0; j < n; ++j) 45 lx[i] = max(lx[i], map[i][j]); 46 for(int i = 0; i < n; ++i) //对n个点匹配 47 { 48 for(int j = 0; j < n; ++j) 49 slack[j] = INT_MAX; 50 while(1) 51 { 52 memset(visitx, false, sizeof(visitx)); 53 memset(visity, false, sizeof(visity)); 54 if(Hungary(i)) //匹配成功 55 break; 56 else //匹配失败,找最小值 57 { 58 temp = INT_MAX; 59 for(int j = 0; j < n; ++j) 60 if(!visity[j]) 61 if(temp > slack[j]) 62 temp = slack[j]; 63 for(int j = 0; j < n; ++j) //更新顶标 64 { 65 if(visitx[j]) 66 lx[j] -= temp; 67 if(visity[j]) 68 ly[j] += temp; 69 else 70 slack[j] -= temp; 71 } 72 } 73 } 74 } 75 } 76 77 int main() 78 { 79 int ans; 80 while(scanf("%d", &n) != EOF) 81 { 82 ans = 0; 83 memset(match, -1, sizeof(match)); 84 for(int i = 0; i < n; ++i) 85 for(int j = 0; j < n; ++j) 86 scanf("%d",&map[i][j]); 87 KM_perfect_match(); 88 for(int i = 0; i < n; ++i) //权值相加 89 ans += map[match[i]][i]; 90 printf("%d\n", ans); 91 } 92 return 0; 93 }