• HDU 2255 二分图最佳匹配


    奔小康赚大钱

    Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 14416    Accepted Submission(s): 6273


    Problem Description
    传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
    这可是一件大事,关系到人民的住房问题啊。村里共有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只适用于完备匹配. 

    代码

    #include <bits/stdc++.h>
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define all(a) (a).begin(), (a).end()
    #define fillchar(a, x) memset(a, x, sizeof(a))
    #define huan printf("
    ")
    #define debug(a,b) cout<<a<<" "<<b<<" "<<endl
    #define ffread(a) fastIO::read(a)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int N = 310;
    const int INF = 0x3f3f3f3f;
    int nx,ny;
    int g[N][N];//二分图描述 11
    int linker[N],lx[N],ly[N];//y 中各点匹配状态,x,y 中的点标号
     int slack[N];
    bool visx[N],visy[N];
    bool DFS(int x)
    {
         visx[x] = true;
         for(int y = 0; y < ny; y++)
        {
             if(visy[y])
                continue;
             int tmp = lx[x] + ly[y] - g[x][y];
             if(tmp == 0)
            {
                 visy[y] = true;
                 if(linker[y] == -1 || DFS(linker[y]))
                {
                     linker[y] = x;
                    return true;
    
                }
    
            }
             else if(slack[y] > tmp)
                 slack[y] = tmp;
        }
         return false;
    }
    int KM()
    {
        memset(linker,-1,sizeof(linker));
        memset(ly,0,sizeof(ly));
        for(int i = 0; i < nx; i++)
        {
            lx[i] = -INF;
            for(int j = 0; j < ny; j++)
                if(g[i][j] > lx[i])
                    lx[i] = g[i][j];
        }
        for(int x = 0; x < nx; x++)
        {
            for(int i = 0; i < ny; i++)
                slack[i] = INF;
            while(true)
            {
                memset(visx,false,sizeof(visx));
                memset(visy,false,sizeof(visy));
                if(DFS(x))
                    break;
                int d = INF;
                for(int i = 0; i < ny; i++)
                    if(!visy[i] && d > slack[i])
                        d = slack[i];
                for(int i = 0; i < nx; i++)
                    if(visx[i])
                        lx[i] -= d;
                for(int i = 0; i < ny; i++)
                {
                    if(visy[i])
                        ly[i] += d;
                    else
                        slack[i] -= d;
                }
            }
        }
        int res = 0;
        for(int i = 0; i < ny; i++)
            if(linker[i] != -1)
                res += g[linker[i]][i];
        return res;
    }
    int main()
    {
        int n;
        while(scanf("%d",&n) == 1)
        {
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    scanf("%d",&g[i][j]);
            nx = ny = n;
            printf("%d
    ",KM());
        }
        return 0;
    }
  • 相关阅读:
    EML格式解析及其访问实现
    Windows Live Writer测试
    这几天为搬房子的事烦死了。
    今天装MSSQL2005时发现有些安装文件要跟2000共享(无法更改安装盘符)
    今天看到一段比较有意思的JS脚本,根据访问速度来选择镜像。
    MS的帮助越来越多视频了。
    邹健写的公交车路线查询(包括转车近到远排列)。
    今天终于搬到这边住了,就是感觉贵了点。
    第一次看到银行系统用DotNet来做。
    这几天上火了
  • 原文地址:https://www.cnblogs.com/stranger-/p/9823267.html
Copyright © 2020-2023  润新知