zoukankan      html  css  js  c++  java
  • A

    传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
    这可是一件大事,关系到人民的住房问题啊。村里共有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
    ",km());
        }
        return 0;
     } 
    
    
    
     
  • 相关阅读:
    bzoj1297: [SCOI2009]迷路
    bzoj1875: [SDOI2009]HH去散步
    bzoj2466: [中山市选2009]树
    bzoj1770: [Usaco2009 Nov]lights 燈
    BZOJ 1965: [Ahoi2005]SHUFFLE 洗牌( 数论 )
    BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )
    BZOJ 1006: [HNOI2008]神奇的国度( MCS )
    BZOJ 1925: [Sdoi2010]地精部落( dp )
    BestCoder Round #57 (div.2)
    BZOJ 1216: [HNOI2003]操作系统( 优先队列 )
  • 原文地址:https://www.cnblogs.com/ylrwj/p/11794782.html
Copyright © 2011-2022 走看看