zoukankan      html  css  js  c++  java
  • HUD:2853-Assignment(KM算法+hash)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2853

    Assignment

    Time Limit: 2000/1000 MS (Java/Others)
    Memory Limit: 32768/32768 K (Java/Others)

    Problem Description

    Last year a terrible earthquake attacked Sichuan province. About 300,000 PLA soldiers attended the rescue, also ALPCs. Our mission is to solve difficulty problems to optimization the assignment of troops. The assignment is measure by efficiency, which is an integer, and the larger the better.
    We have N companies of troops and M missions, M>=N. One company can get only one mission. One mission can be assigned to only one company. If company i takes mission j, we can get efficiency Eij.
    We have a assignment plan already, and now we want to change some companies’ missions to make the total efficiency larger. And also we want to change as less companies as possible.

    Input

    For each test case, the first line contains two numbers N and M. N lines follow. Each contains M integers, representing Eij. The next line contains N integers. The first one represents the mission number that company 1 takes, and so on.
    1<=N<=M<=50, 1

    Output

    For each the case print two integers X and Y. X represents the number of companies whose mission had been changed. Y represents the maximum total efficiency can be increased after changing.

    Sample Input

    3 3
    2 1 3
    3 2 4
    1 26 2
    2 1 3
    2 3
    1 2 3
    1 2 3
    1 2

    Sample Output

    2 26
    1 2


    解题心得:

    • 题意就是先给你一个匹配,要你重新匹配,匹配之后的权值最大,并且要求你改变原先匹配次数要最小。

    • 匹配出来的权值最大,就是一个KM算法,但是要改变次数最小就要一点小技巧了,原本想的是在原先的匹配方案上加一就可以了,这样在面对大小一样的情况下可以优先选择,但是有个问题就是很可能加一之后和另一个更大值重合了。所以需要先乘以一个很大的值,在加一就可以可以避免重合的问题,也就是hash的问题。然后再直接对比现在的匹配情况和之前的匹配情况。


    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 55;
    int maps[maxn][maxn];
    int ly[maxn],lx[maxn],match[maxn],pre_match[maxn],slack[maxn];
    bool visx[maxn],visy[maxn];
    int n,m;
    
    void init()
    {
        memset(ly,0,sizeof(ly));
        memset(lx,0,sizeof(lx));
        memset(match,-1,sizeof(match));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&maps[i][j]);
                maps[i][j] *= 100;
                if(maps[i][j] > lx[i])
                    lx[i] = maps[i][j];
            }
        for(int i=1;i<=n;i++)
            scanf("%d",&pre_match[i]);
    }
    
    bool dfs(int x)
    {
        visx[x] = true;
        for(int i=1;i<=m;i++)
        {
            if(visy[i])
                continue;
            int temp;
            temp = lx[x] + ly[i] - maps[x][i];
            if(!temp)
            {
                visy[i] = true;
                if(match[i] == -1 || dfs(match[i]))
                {
                    match[i] = x;
                    return true;
                }
            }
            else if(temp < slack[i])
                slack[i] = temp;
        }
        return false;
    }
    
    int get_pre_sum()
    {
        int sum = 0;
        for(int i=1;i<=n;i++)
        {
            sum += maps[i][pre_match[i]]/100;
            maps[i][pre_match[i]]++;
            if(maps[i][pre_match[i]] > lx[i])
                lx[i] = maps[i][pre_match[i]];
        }
        return sum;
    }
    
    void KM()
    {
        int pre_sum = get_pre_sum();
        for(int i=1;i<=n;i++)
        {
            memset(slack,0x3f,sizeof(slack));
            while(1)
            {
                memset(visx,0,sizeof(visx));
                memset(visy,0,sizeof(visy));
                if(dfs(i))
                    break;
    
                int temp = 0x3f3f3f3f;
                for(int j=1;j<=m;j++)
                    if(!visy[j] && temp > slack[j])
                        temp = slack[j];
                for(int j=1;j<=n;j++)
                {
                    if(visx[j])
                        lx[j] -= temp;
                }
                for(int j=1;j<=m;j++)
                {
                    if(visy[j])
                        ly[j] += temp;
                    else
                        slack[j] -= temp;
                }
            }
        }
        int ans1,ans2;
        ans1 = ans2 = 0;
        for(int i=1;i<=m;i++)
            ans1 += maps[match[i]][i];
        for(int i=1;i<=n;i++)
        {
            if(match[pre_match[i]] != i)//前后对比
                ans2++;
        }
        printf("%d %d
    ",ans2,ans1/100-pre_sum);
        //也可以写成:printf("%d %d
    ",ans1%100,ans1/100-pre_sum);
        return ;
    }
    
    int main()
    {
        while(~scanf("%d%d",&n,&m))
        {
            init();
            KM();
        }
        return 0;
    }
    
  • 相关阅读:
    IDEA 配置Springboot项目热部署
    一文读懂类加载机制
    面试必问的MySQL锁与事务隔离级别
    工作中遇到的99%SQL优化,这里都能给你解决方案(三)
    谁有好的oracle数据库学习书籍,麻烦提供一下,感激不尽
    静态资源上传至远程ftp服务器,ftp工具类封装
    进程和线程,并发和并行,同步和异步,高并发和多线程,理一理概念
    使用springboot集成腾讯云短信服务,解决配置文件读取乱码问题
    曾经天真的以为单例只有懒汉和饿汉两种!原来单例模式还能被破解!!!
    了解一下zookeeper,搭建单机版和集群版的环境玩玩,需要手稿的,留下邮箱
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107231.html
Copyright © 2011-2022 走看看