HDU 2853 Assignment(二分图最优匹配)

题意:给定一个二分图,N个点对应M个点,两两之间存在一组关系,每组关系一个权值。题目中了给定了一个匹配方案,现在要求满足这组关系中的最大的匹配权值在原方案上增长了多少?并且还要求出在原匹配方案上改变(最少)多少条边才能够得到这个最大匹配?

思路:最优权值匹配很好求,直接用KM模板,但是要在原匹配边的基础上使得改变的边最少,这里需要特殊处理:

           以下转自网上,写得很好。

           这里由于左边点集有N个点,且M>=N。那么最终的最优匹配必然有N条边。我们让原图中的每条边的权值都乘以(N+1),即扩大N+1倍。且如果某条边本来就是原匹配用的其中一条边,那么该边权值在扩大N+1倍后,再加1。 所以任意一条边的权值只能是N+1的倍数 或 (N+1的倍数)+1,我们将要在这种权值的边中选出N条来(想想如果我们最终在新二分图求出的最优权值和==(N+1)的倍数,那么说明什么?说明我们最优匹配中,一条老边都没有复用.虽然老边的权值有加1的优势 )。

           最终我们得到的最优权值和ans除以(N+1)就是最优权值解(因为就算我们原封不动的还用以前的匹配,也就是在所有权值的基础上加了N1,此时/(N+1),整除归0)。

           最终ans%(N+1)就是我们复用旧边的条数(上述两条结论仔细验证)。

           下面来论证一下为什么上面的所有边权值*(N+1),老边还+1”这个策略可行?

            假设原图有唯一最优权值的解(即所有其他的匹配方案边的权值总和都要小于该解的权值和)。

            那么所有边权值*(N+1),老边还+1”之后.假设原先次优解的权值只比最优解的权值少1,

         且次优解匹配用的都是原匹配边(即操作后次优解权值和增加的最多)

         且最优解匹配用的都是原非匹配边(即最优解权值和增加的最少). 

         就算是这样,操作后,最优解的权值依然正好比次优解权值和大1. 

         所以如果最优解唯一,我们不会丢失最优解.

            下面假设原图最优解方案不唯一,即有多个最优解方案可以得到最优解. 当时我们能肯定 那个用到老边最多的最优解方案 在我们所有边权值*(N+1),老边还+1”操作后,其权值必然是所有解里面最大的. 即它变成了新的最优解,我们自然选它.

             上述两段论证了为什么我们所有边权值*(N+1),老边还+1”这个操作的可行性.


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=50+10;

struct Max_Match
{
    int n,m;
    int W[maxn][maxn],Lx[maxn],Ly[maxn];
    bool S[maxn],T[maxn];
    int left[maxn];

    bool match(int i)
    {
        S[i]=true;
        for(int j=1;j<=m;j++)if(Lx[i]+Ly[j]==W[i][j] && !T[j])
        {
            T[j]=true;
            if(left[j]==-1 || match(left[j]))
            {
                left[j]=i;
                return true;
            }
        }
        return false;
    }

    void update()
    {
        int a=1<<30;
        for(int i=1;i<=n;i++)if(S[i])
        for(int j=1;j<=m;j++)if(!T[j])
            a = min(a,Lx[i]+Ly[j]-W[i][j]);
        for(int i=1;i<=n;i++)
            if(S[i]) Lx[i] -=a;
        for(int j=1;j<=m;j++)
            if(T[j]) Ly[j] +=a;
    }

    int solve(int n,int m)
    {
        this->n=n;
        this->m=m;
        memset(left,-1,sizeof(left));
        memset(Lx,0,sizeof(Lx));
        memset(Ly,0,sizeof(Ly));

        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            Lx[i]=max(Lx[i], W[i][j]);
        for(int i=1;i<=n;i++)
        {
            while(true)
            {
                memset(S,0,sizeof(S));
                memset(T,0,sizeof(T));
                if(match(i)) break;
                else update();
            }
        }

        int ans=0;
        for(int i=1;i<=m;i++)if(left[i]!=-1)
            ans += W[left[i]][i];
        return ans;
    }
}KM;

int W[maxn][maxn];

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)==2)
    {
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&W[i][j]);
            KM.W[i][j] = W[i][j]*(n+1);
        }

        int old_val=0;
        for(int i=1;i<=n;i++)
        {
            int j;
            scanf("%d",&j);
            old_val += W[i][j];
            ++KM.W[i][j];
        }
        int ans = KM.solve(n,m);
        printf("%d %d\n",n-ans%(n+1),ans/(n+1)-old_val);
    }
    return 0;
}

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<Eij<=10000. 
Your program should process to the end of file.
 

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
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值