zoukankan      html  css  js  c++  java
  • HDU 2255 ——奔小康赚大钱——————【KM算法裸题】

    奔小康赚大钱
    Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

    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
     
     
    解题思路:最优完美匹配。套模板就行了。
     
    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #include<vector>
    using namespace std;
    const int maxn = 550;
    const int INF = 0x3f3f3f3f;
    int nx, ny, lx[maxn], ly[maxn];
    bool visx[maxn], visy[maxn];
    int linker[maxn], slack[maxn];
    int G[maxn][maxn];
    bool dfs(int x){
        visx[x] = 1;                    //标记X的匈牙利树节点
        for(int y = 1; y <= ny; y++){
            if(visy[y]) continue;
            int tmp = lx[x] + ly[y] - G[x][y];
            if(tmp == 0){   //找到了一条可以加入相等子图的新边
                visy[y] = 1;    //标记Y的匈牙利树节点
                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));            //初始化Y节点顶标
        for(int i = 1; i <= nx; i++){
            lx[i] = -INF;
            for(int j = 1; j <= ny; j++){
                if(lx[i] < G[i][j]){
                    lx[i] = G[i][j];        //初始化X节点顶标
                }
            }
        }
        for(int x = 1; x <= nx; x++){       //找每个X的增广路
            for(int i = 1; i <= ny; i++){   //初始化松弛量
                slack[i] = INF;
            }
            while(true){
                memset(visx,0,sizeof(visx));
                memset(visy,0,sizeof(visy));
                if(dfs(x)) break;               //找到了增广路
                int d = INF;
                for(int i = 1; i <= ny; i++){
                    if(!visy[i] && d > slack[i]){   //Yi不在匈牙利树(交错树)中
                        d = slack[i];
                    }
                }
                for(int i = 1; i <= nx; i++){       //Xi在匈牙利树中,更新顶标
                    if(visx[i]){
                        lx[i] -= d;
                    }
                }
                for(int i = 1; i <= ny; i++){
                    if(visy[i]){                //Yi在匈牙利树中,更新顶标
                        ly[i] += d;
                    }else{                      //更新松弛量
                        slack[i] -= d;
                    }
                }
            }
        }
        int ret = 0;
        for(int i = 1; i <= ny; i++){          //求和
            if(linker[i] != -1){
                ret += G[linker[i]][i];
            }
        }
        return ret;
    }
    int main(){
        int n;
        while(scanf("%d",&n)!=EOF){
            memset(G,0,sizeof(G));
            int c;
            for(int i = 1; i <= n; i++){
                for(int j = 1; j <= n; j++){
                    scanf("%d",&c);
                    G[i][j] = c;
                }
            }
            nx = ny = n;
            int res = KM();
            printf("%d
    ",res);
        }
        return 0;
    }
    

      

     
  • 相关阅读:
    topcoder srm 445 div1
    topcoder srm 440 div1
    topcoder srm 435 div1
    topcoder srm 430 div1
    topcoder srm 400 div1
    topcoder srm 380 div1
    topcoder srm 370 div1
    topcoder srm 425 div1
    WKWebView强大的新特性
    Runtime那些事
  • 原文地址:https://www.cnblogs.com/chengsheng/p/4964051.html
Copyright © 2011-2022 走看看