zoukankan      html  css  js  c++  java
  • HDU 2255

    题意

    有n户人家和n间房。现在给出每户人家对每一间房的报价,求怎样分配房子才能使政府收入最大,输出最大收入。

    思路

    带权二分图的最优匹配问题,可由KM算法解决

    km算法入门

    【原创】我的KM算法详解
    顶标内容讲的很好:KM算法
    松弛度内容讲的比较好:二分图的最佳完美匹配——KM算法
    匈牙利算法和FF算法结合得到KM算法讲的很详细:二分图匹配之最佳匹配——KM算法
    最佳讲解博客推荐:我对KM算法的理解

    AC代码

    kuangbin的KM算法模板

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    const int maxn = 300+5;
    const int INF = 0x3f3f3f3f;
    int nx, ny;
    int g[maxn][maxn];
    int linker[maxn], lx[maxn], ly[maxn];
    int slack[maxn];
    bool visx[maxn], visy[maxn];
    
    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(1){
                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))
        {
            nx = ny = n;
            for(int i = 0; i < nx; i++){
                for(int j = 0; j < ny; j++){
                    scanf("%d",&g[i][j]);
                }
            }
            printf("%d
    ", KM());
        }
        return 0;
    }
  • 相关阅读:
    个人总结08
    npm快速入门
    Activity简介
    SELinux
    正则表达式学习笔记(二)表达式的匹配原理
    git学习笔记(一)
    使用VSFTPD传输文件
    正则表达式学习笔记(一)正则表达式入门
    Linux基础(一)磁盘分区
    Shell脚本笔记(九)数组
  • 原文地址:https://www.cnblogs.com/JinxiSui/p/9740517.html
Copyright © 2011-2022 走看看