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; }