A - 奔小康赚大钱(KM算法)
传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
这可是一件大事,关系到人民的住房问题啊。村里共有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
这是KM算法的一道模板题
KM算法就是的最大权匹配(与匈牙利算法不同的是KM需要考虑权值)
依旧是男女配对
https://www.cnblogs.com/wenruo/p/5264235.html(请参考这篇博客,很详细)
该题中的村民就相当于女生,房子就相当于男生,若尽可能多的满足大家需求,就要一次一次配对,适当降低部分人的
标准,配对过程是一个递归过程
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int maxn=310; const int inf=0x3f3f3f3f; int yuji[maxn][maxn];//记录每个村民对每个房子的所支付金额 int cunmin[maxn]; int fangzi[maxn]; bool vis_cunmin[maxn]; bool vis_fangzi[maxn]; int match[maxn]; int sla[maxn]; int n; bool dfs(int x) { vis_cunmin[x]=true; for(int f=0;f<n;f++) { if(vis_fangzi[f])continue; int g=cunmin[x]+fangzi[f]-yuji[x][f]; if(g==0) { vis_fangzi[f]=true; if(match[f]==-1||dfs(match[f])) { match[f]=x; return true; } } else { sla[f]=min(sla[f],g); } } return false; } int km() { memset(match,-1,sizeof(match)); memset(fangzi,0,sizeof(fangzi)); for(int i=0;i<n;i++) { cunmin[i]=yuji[i][0]; for(int j=1;j<n;j++) { cunmin[i]=max(cunmin[i],yuji[i][j]); } } for(int i=0;i<n;i++) { fill(sla,sla+n,inf); while(1) { memset(vis_cunmin,false,sizeof(vis_cunmin)); memset(vis_fangzi,false,sizeof(vis_fangzi)); if(dfs(i)) break; int d=inf; for(int j=0;j<n;j++) if(!vis_fangzi[j]) d=min(d,sla[j]); for(int j=0;j<n;j++) { if(vis_cunmin[j]) cunmin[j]-=d; if(vis_fangzi[j]) fangzi[j]+=d; else sla[j]-=d; } } } int res=0; for(int i=0;i<n;i++) res+=yuji[match[i]][i]; return res; } int main() { while(~scanf("%d",&n)) { for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",&yuji[i][j]); printf("%d\n",km()); } return 0; }