T66597 小xzy的任务 题解
T66597 小xzy的任务
题目背景
今天,小xzy的班主任交给他一个严肃的任务,匹配羽毛球运动员! ! !
题目描述
羽毛球队有男女运动员各n人。给定2个n×n矩阵P和Q。Pij是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势;Qij是女运动员ii和男运动员j配合的女运动员竞赛优势。由于技术配合和心理状态等各种因素影响,Pij不一定等于Qji。男运动员ii和女运动员jj配对组成混合双打的男女双方竞赛优势为Pij∗Qji。设计一个算法,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。
编程任务
设计一个算法,对于给定的男女运动员竞赛优势,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。
输入输出格式
输入格式:
第一行有1 个正整数n (2≤n≤1000)。接下来的2n行,每行n个数。前n行是p,后n行是q。
输出格式:
一个整数,计算出的男女双方竞赛优势的总和的最大值。
输入输出样例
说明
0≤n≤1000,0≤Pij,Qij≤1000
第一个测试点:n≤100
这题我们把男运动员和女运动员看成两个集合,于是这题便可以看成是带权二分图匹配。
带权二分图匹配通常使用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;
}
任何一个伟大的思想,都有一个微不足道的开始。
-  
三年OI一场空,三道神题见祖宗
 -  
竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生。
 -  
回首向来萧瑟处,归去,也无风雨也无晴。
 

                
            
        
浙公网安备 33010602011771号