hdu 2255 奔小康赚大钱 最大权匹配KM
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255
传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。
另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).
这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。
另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).
题意描述:由于此题为中文题,这里不作翻译。
算法分析:最大权匹配问题,KM算法的入门题。百度KM算法有很多相关介绍的,这里不再累述。说明一点,KM优化:slack数组保存的是在dfs找增广路的时候随便求出Y集(二分图:X集和Y集)中不在相等子图中的每个y的值min(lx[x]-ly[y]-w[x][y]),最终算法复杂度为O(n^3)。
对编译知识不是很了解,为什么这道题G++提交TLE而C++提交AC,感觉很厉害很高级的样子。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 0x7fffffff 10 using namespace std; 11 const int maxn=300+10; 12 13 int n,nx,ny; 14 int lx[maxn],ly[maxn],visx[maxn],visy[maxn]; 15 int link[maxn],slack[maxn]; 16 int w[maxn][maxn]; 17 18 int dfs(int x) 19 { 20 visx[x]=1; 21 for (int y=1 ;y<=ny ;y++) 22 { 23 if (visy[y]) continue; 24 int t=lx[x]+ly[y]-w[x][y]; 25 if (t==0) 26 { 27 visy[y]=1; 28 if (link[y]==-1 || dfs(link[y])) 29 { 30 link[y]=x; 31 return 1; 32 } 33 } 34 else if (slack[y]>t) slack[y]=t; 35 } 36 return 0; 37 } 38 39 int KM() 40 { 41 memset(ly,0,sizeof(ly)); 42 memset(link,-1,sizeof(link)); 43 for (int x=1 ;x<=nx ;x++) 44 { 45 lx[x]=-inf; 46 for (int y=1 ;y<=ny ;y++) 47 lx[x]=max(lx[x],w[x][y]); 48 } 49 for (int x=1 ;x<=nx ;x++) 50 { 51 for (int j=1 ;j<=ny ;j++) slack[j]=inf; 52 while (1) 53 { 54 memset(visx,0,sizeof(visx)); 55 memset(visy,0,sizeof(visy)); 56 if (dfs(x)) break; 57 int d=inf; 58 for (int j=1 ;j<=ny ;j++) 59 { 60 if (!visy[j] && slack[j]<d) 61 d=slack[j]; 62 } 63 for (int i=1 ;i<=nx ;i++) 64 if (visx[i]) lx[i] -= d; 65 for (int i=1 ;i<=ny ;i++) 66 { 67 if (visy[i]) ly[i] += d; 68 else slack[i] -= d; 69 } 70 } 71 } 72 int ans=0; 73 for (int i=1 ;i<=ny ;i++) 74 if (link[i]!=-1) ans += w[link[i] ][i]; 75 return ans; 76 } 77 78 int main() 79 { 80 while (scanf("%d",&n)!=EOF) 81 { 82 nx=ny=n; 83 for (int i=1 ;i<=n ;i++) 84 { 85 for (int j=1 ;j<=n ;j++) 86 scanf("%d",&w[i][j]); 87 } 88 printf("%d\n",KM()); 89 } 90 return 0; 91 }