• 【hdu2055】奔小康赚大钱(最佳匹配)


    Problem Description
    传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
    这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。
    另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).
    Input
    输入数据包含多组测试用例,每组数据的第一行输入n,表示房子的数量(也是老百姓家的数量),接下来有n行,每行n个数表示第i个村名对第j间房出的价格(n<=300)。
     
    Output
    请对每组数据输出最大的收入值,每组的输出占一行。
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define re return
    #define ll long long
    #define inc(i,l,r) for(int i=l;i<=r;++i)
    
    const int inf=2147483647,maxn=305;
    using namespace std;
    template<typename T>inline void rd(T&x)
    {
        char c;bool f=0;
        while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
        x=c^48;
        while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
        if(f)x=-x;
    }
    
    int n;
    int ex1[maxn];//1的期望度
    int ex2[maxn];//2的期望度
    int pri[maxn][maxn];//价格
    int match[maxn];//匹配2的1
    int vis1[maxn];//1是否被访问过
    int vis2[maxn];//2是否访问过
    int slack[maxn];//最小差多少,2可以被1访问
    
    inline bool dfs(int x)
    {
        vis1[x]=1;//标记1访问
        inc(i,1,n)
        {
            if(vis2[i])continue;
            if(ex1[x]+ex2[i]==pri[x][i])//达到访问要求
            {
                vis2[i]=1;标记2访问
                if(!match[i]||dfs(match[i]))
                {
                    match[i]=x;
                    re 1;
                }
            }
            else slack[i]=min(slack[i],ex1[x]+ex2[i]-pri[x][i]);
    //2差值统计
        }
        re 0;
    }
    
    inline void KM()
    {
        inc(i,1,n)match[i]=ex2[i]=0;
    //刷新
        inc(i,1,n)
        {
            inc(j,1,n)
            slack[j]=inf;
            while(2333)
            {
                inc(j,1,n)vis1[j]=vis2[j]=0;
                if(dfs(i))break;
                int d=inf;
                inc(j,1,n)
                if(!vis2[j])
                    d=min(d,slack[j]); 
    //最小改变度
                inc(j,1,n)
                {
                    if(vis1[j])ex1[j]-=d;
                    if(vis2[j])ex2[j]+=d;
                    else slack[j]-=d;
    //分别改变
                }
            }
        }
    }
    
    int main()
    {
        while(~scanf("%d",&n))
        {
            
            inc(i,1,n)ex1[i]=-inf;
            inc(i,1,n)    
            inc(j,1,n)
            {
                rd(pri[i][j]);
                ex1[i]=max(ex1[i],pri[i][j]);
            }
            int ans=0;
            KM();
            for(int i=1;i<=n;++i)
            ans+=pri[match[i]][i];
            printf("%d
    ",ans);
        }
    
        
        re 0;
    }
  • 相关阅读:
    Linux基础(14)进程通信 IPCs
    Linux基础(13)进程基础
    Linux基础(10)AIO项目设计与POSIX文件操作和目录管理
    Linux基础(09)aio高级编程
    Linux基础(08)信号通信机制
    Linux基础(06)IO复用
    Linux基础(05)socket编程
    LInux基础(04)项目设计一(理解链表管理协议的代码架构)
    C#关于一个程序,只可以有一种实例的方法
    C#application.exit()和environment.Exit(0)比较
  • 原文地址:https://www.cnblogs.com/lsyyy/p/11366195.html
Copyright © 2020-2023  润新知