【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\n",ans);
    }

    
    re 0;
}

 

posted @ 2019-08-16 20:30  凉如水  阅读(193)  评论(0编辑  收藏  举报