HDU 2853 (KM最大匹配)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853

题目大意:二分图匹配费用流。①最大匹配②最小原配变动

解题思路

如果去掉第二个要求,那么就是裸KM。

然而加上第二个要求,那么就需要一种新的建图方式。

建图

对于输入矩阵,每一条边,cost扩大K倍($K=n+1$)

对于原配,每一条边cost在扩大K倍基础上+1

KM

统计cost时,直接把cost整除K,然后累加。

并且Hash一下原配边的变动情况。

扩大K倍的作用

准确来说,K倍是为了+1而存在的。由于要优先考虑原配边,所以cost要大些。

但是,加大的cost又要使得最后好统计真实的cost。所以选择扩大K倍,然后整除K,这样,+1会被直接舍掉。

K=n+1是防止n=1的情况被卡姿势。

代码

#include "iostream"
#include "cstdio"
#include "cstring"
#include "algorithm"
using namespace std;
#define maxn 55
int n,m,Hash[maxn],tmp,old,K;
int link[maxn],LX[maxn],RX[maxn],W[maxn][maxn],slack[maxn],e[maxn][maxn];
bool S[maxn],T[maxn];
const int inf=0x3f3f3f3f;
bool dfs(int u)
{
    S[u]=true;
    for(int v=1;v<=m;v++)
    {
        if(T[v]) continue;
        int t=LX[u]+RX[v]-W[u][v];
        if(!t)
        {
            T[v]=true;
            if(!link[v]||dfs(link[v]))
            {
                link[v]=u;
                return true;
            }
        }
        else if(t<slack[v]) slack[v]=t;
    }
    return false;
}
void update()
{
    int a=inf;
    for(int i=1;i<=m;i++) //ny
       if(!T[i]&&slack[i]<a) a=slack[i];
    for(int i=1;i<=n;i++)  //nx
        if(S[i]) LX[i]-=a;
    for(int i=1;i<=m;i++) //ny
    {
        if(T[i]) RX[i]+=a;
        else slack[i]-=a;
    }
}
void KM()
{
    memset(link,0,sizeof(link));
    memset(RX,0,sizeof(RX));
    for(int i=1;i<=n;i++) //nx
        for(int j=1;j<=m;j++) //ny
            LX[i]=max(LX[i],W[i][j]);
    for(int i=1;i<=n;i++) //nx
    {
        for(int j=1;j<=m;j++) //ny
            slack[j]=inf;
        while(1)
        {
            memset(S,0,sizeof(S));
            memset(T,0,sizeof(T));
            if(dfs(i)) break;
            else update();
        }
    }
    int res=0,change=0;
    for(int i=1;i<=m;i++) //ny
    {
       if(link[i])
       {
           res+=(W[link[i]][i]/K);
           if(Hash[i]!=link[i]) change++;
       }
    }
    printf("%d %d\n",change,res-old);
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
       memset(W,0,sizeof(W));
       memset(Hash,0,sizeof(Hash));
       old=0;K=n+1;
       for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
        {
            scanf("%d",&W[i][j]);
            W[i][j]*=K;
        }
       for(int i=1;i<=n;i++)
       {
           scanf("%d",&tmp);
           old+=(W[i][tmp]/K);
           Hash[tmp]=i;
           W[i][tmp]++;
       }
       KM();
       memset(slack,0,sizeof(slack));
       memset(LX,0,sizeof(LX));
    }
    return 0;
}
时间: 2024-10-13 06:07:16

HDU 2853 (KM最大匹配)的相关文章

HDU 2853 Assignment(KM最大匹配好题)

HDU 2853 Assignment 题目链接 题意:现在有N个部队和M个任务(M>=N),每个部队完成每个任务有一点的效率,效率越高越好.但是部队已经安排了一定的计划,这时需要我们尽量用最小的变动,使得所有部队效率之和最大.求最小变动的数目和变动后和变动前效率之差. 思路:对于如何保证改变最小,没思路,看了别人题解,恍然大悟,表示想法非常机智 试想,如果能让原来那些匹配边,比其他匹配出来总和相同的权值还大,对结果又不影响,那就简单了,这个看似不能做到,其实是可以做到的 数字最多选出50个,所

HDU 3523 Image copy detection(KM最大匹配)

HDU 3523 Image copy detection 题目链接 题意:这题其实题意读懂就简单了,说白了就是1-n放到1-n列,每列的值为每列上数字和该数字的差的绝对值,然后求总和最小 思路:就一KM最大匹配 代码: #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std;

HDU 3722 Card Game(KM最大匹配)

HDU 3722 Card Game 题目链接 题意:给定一些字符串,每次可以选两个a,b出来,a的前缀和b的后缀的最长公共长度就是获得的值,字符串不能重复选,问最大能获得多少值 思路:KM最大匹配,两两串建边,跑最大匹配即可 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int MAXNODE

HDU 3718 Similarity(KM最大匹配)

HDU 3718 Similarity 题目链接 题意:给定一个标准答案字符串,然后下面每一行给一个串,要求把字符一种对应一种,要求匹配尽量多 思路:显然的KM最大匹配问题,位置对应的字符连边权值+1 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int MAXNODE = 27; typede

HDU 2853 &amp;&amp; HDU 3315

http://acm.hdu.edu.cn/showproblem.php?pid=2853 题意:给一个n-m二分图,边权用一个n*m的矩阵表示,给出初始匹配,求二分图完美匹配相比初始匹配改变了几条边以及改变的数值 这类题的主要思想是增加原配边的权值,但又不影响最后结果. 步骤1:观察顶点数,每条边乘一个大于顶点数的数v 步骤2:对于原配边,每边加1(注意步骤2可以保证km()/v的结果与原结果相同) 步骤3:求完美匹配,答案为res,改变的边数=n-res%v(res%v表示完美匹配中有多少

hdu 4862 KM算法 最小K路径覆盖的模型

http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过所有的点一次并且仅仅一次, 建图是问题: 我自己最初就把n*m 个点分别放入X集合以及Y集合,再求最优匹配,然后连样例都过不了,而且其实当时解释不了什么情况下不能得到结果,因为k此这个条件相当于没用上... 建图方法: 1.X集合和Y集合都放入n*m+k个点,X中前n*m个点和Y中前n*m个点之间,如果格子里的值相等,权就是(收益-耗费),不等就是(-耗费),因为要的是最大收益

HDU 1528 (二分图最大匹配 + 最小覆盖, 14.07.17)

Problem Description Adam and Eve play a card game using a regular deck of 52 cards. The rules are simple. The players sit on opposite sides of a table, facing each other. Each player gets k cards from the deck and, after looking at them, places the c

hdu 2853 Assignment 费用流

就是本来就给出了一个匹配,然后让你求一个权值最大的匹配,并且和初始匹配变动最小. #include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=400; const int MAXE=20000000; const int inf=1<<30; int head[N],s,t,cnt,ans; int d[N],pre[N]; bool

HDU 2853 最大匹配&amp;KM模板

http://acm.hdu.edu.cn/showproblem.php?pid=2853 这道题初看了没有思路,一直想的用网络流如何解决 参考了潘大神牌题解才懂的 最大匹配问题KM 还需要一些技巧来解决最小变动, 做法是:把原先的邻接矩阵每个数扩大k倍(k>n) 为了突出原先的选择,也就是同等情况下优先选择原来的方案 给原来的方案对应矩阵内的数据+1 那么 最终得出的最大匹配值/k=真实的最大匹配 最终得出的最大匹配值%k=原来的方案采用了几个 这里的KM留下来做模板 /* 二分图最佳匹配