T66597 小xzy的任务 题解

T66597 小xzy的任务

题目背景

今天,小xzy的班主任交给他一个严肃的任务,匹配羽毛球运动员! ! !

题目描述

羽毛球队有男女运动员各n人。给定2n×n矩阵PQPij是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势;Qij是女运动员ii和男运动员j配合的女运动员竞赛优势。由于技术配合和心理状态等各种因素影响,Pij不一定等于Qji。男运动员ii和女运动员jj配对组成混合双打的男女双方竞赛优势为PijQji。设计一个算法,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。

编程任务

设计一个算法,对于给定的男女运动员竞赛优势,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。

输入输出格式

输入格式:

第一行有1 个正整数n (2n1000)。接下来的2n行,每行n个数。前n行是p,后n行是q。

输出格式:

一个整数,计算出的男女双方竞赛优势的总和的最大值。

输入输出样例

输入样例#1: 
3
10 2 3
2 3 4
3 4 5
2 2 2
3 5 3
4 5 1
输出样例#1: 
52

说明

0n1000,0Pij,Qij1000

第一个测试点:n100

这题我们把男运动员和女运动员看成两个集合,于是这题便可以看成是带权二分图匹配。

带权二分图匹配通常使用KM算法。

不了解KM算法的请移步。

code:

#include <cstdio>
const int MAXN=2005;
const int INF=0x3f3f3f3f;
int n,now=0;
int rela[MAXN][MAXN],match[MAXN];
int ex_boy[MAXN],ex_girl[MAXN],slack[MAXN];
int vis_boy[MAXN],vis_girl[MAXN];
int boy[MAXN][MAXN],girl[MAXN][MAXN];

void read(int &x)
{
	int out=1;
	char c;x=0;
	while(c<'0' || c>'9'){if(c=='-')out=-1;c=getchar();}
	while(c>='0'&&c<='9')
	{
		x=x*10+c-48;
		c=getchar();
	}
	x=x*out;
}

void write(long long x)
{
	if(x>10)write(x/10);
	putchar(x%10+48);
}

void init()
{
    read(n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)read(boy[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)read(girl[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            rela[i][j]=boy[i][j]*girl[j][i];
}

int dfs(int x)
{
    int cp;
    vis_girl[x]=now;
    for(int y=1;y<=n;y++)
    {
        if(vis_boy[y]==now)continue;
        cp=ex_girl[x]+ex_boy[y]-rela[x][y];
        if(cp==0)
        {
            vis_boy[y]=now;
            if((match[y]==0)||dfs(match[y]))
            {
                match[y]=x;return true;
            }
        }
        else if(cp<slack[y])slack[y]=cp;
    }
    return false;
}

long long KM()
{
    for(int i=1;i<=n;i++)
    {
        match[i]=ex_girl[i]=ex_boy[i]=0;
        for(int j=1;j<=n;j++)
            if(rela[i][j]>ex_girl[i])ex_girl[i]=rela[i][j];
    } 
    for(int i=1;i<=n;i++)
    {
		now=0;
		for(int j=1;j<=n;j++)
		{
			slack[j]=INF;
			vis_boy[j]=vis_girl[j]=0;
		}
        while(1)
        {
            now++;
            if(dfs(i))break;
            int d=INF;
            for(int j=1;j<=n;j++)if(vis_boy[j]!=now&&slack[j]<d)d=slack[j];
            for(int j=1;j<=n;j++)
            {
                if(vis_girl[j]==now)ex_girl[j]-=d;
                if(vis_boy[j]==now)ex_boy[j]+=d;
                else slack[j]-=d;
            }
        }
    }
    long long res=0;
    for(int i=1;i<=n;i++)res+=rela[match[i]][i];
    return res;
}

int main()
{
    init();
    write(KM());
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/lzxzy-blog/p/xinzhaoyang.html