洛谷——P1559 运动员最佳匹配问题
题目描述
羽毛球队有男女运动员各n人。给定2 个n×n矩阵P和Q。P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势;Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势。由于技术配合和心理状态等各种因素影响,P[i][j]不一定等于Q[j][i]。男运动员i和女运动员j配对组成混合双打的男女双方竞赛优势为P[i][j]*Q[j][i]。设计一个算法,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。
输入输出格式
输入格式:
第一行有1 个正整数n (1≤n≤20)。接下来的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 思路 代码:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 40 #define maxn 9999999 using namespace std; int n,a[N][N],b[N][N],love[N][N]; bool vis_boy[N],vis_girl[N]; int pre[N],remain[N],ex_girl[N],ex_boy[N]; int read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) f=-1; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();} return x*f; } int dfs(int girl) { vis_girl[girl]=true; for(int i=1;i<=n;i++) { if(vis_boy[i]) continue; int ex=ex_boy[i]+ex_girl[girl]-love[girl][i]; if(ex==0) { vis_boy[i]=true; if(pre[i]==-1||dfs(pre[i])) {pre[i]=girl; return 1;} } else remain[i]=min(remain[i],ex); } return false; } int km() { memset(ex_boy,0,sizeof(ex_boy)); memset(pre,0,sizeof(pre)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) ex_girl[i]=max(ex_girl[i],love[i][j]); for(int i=1;i<=n;i++) { memset(remain,0x7fff,sizeof(remain)); while(1) { memset(vis_boy,0,sizeof(vis_boy)); memset(vis_girl,0,sizeof(vis_girl)); if(dfs(i)) break; int d=maxn; for(int i=1;i<=n;i++) if(!vis_boy[i]) d=min(d,remain[i]); for(int i=1;i<=n;i++) { if(vis_boy[i]) ex_girl[i]-=d; if(vis_girl[i]) ex_boy[i]+=d; else remain[i]-=d; } } } int ans=0; for(int i=1;i<=n;i++) ans+=love[pre[i]][i]; return ans; } int main() { n=read(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=read(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) b[i][j]=read(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) love[i][j]=a[i][j]*b[j][i]; printf("%d\n",km()); return 0; }
#include<cstdio> #include<iostream> #define MAXN 110 #define INF 1000000000 using namespace std; int lx[MAXN],ly[MAXN]; int f[MAXN][MAXN],n,m,pre[MAXN],pre2[MAXN]; bool vx[MAXN],vy[MAXN]; inline void read(int&x) { int f=1;x=0;char c=getchar(); while(c>‘9‘||c<‘0‘) {if(c==‘-‘) f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘) x=10*x+c-48,c=getchar(); x=x*f; } inline void pra() { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) lx[i]=max(lx[i],f[i][j]); } inline bool find(int u) { vx[u]=true; for(int i=1;i<=m;i++) { if(lx[u]+ly[i]==f[u][i]&&!vy[i]) { vy[i]=true; if(!pre[i]||find(pre[i])) { pre[i]=u; pre2[u]=i; return true; } } } return false; } inline void renew() { int t=INF; for(int i=1;i<=n;i++) if(vx[i]) for(int j=1;j<=m;j++) if(!vy[j]) t=min(t,lx[i]+ly[j]-f[i][j]); for(int i=1;i<=n;i++) if(vx[i]) lx[i]-=t; for(int j=1;j<=m;j++) if(vy[j]) ly[j]+=t; } inline void km() { for(int i=1;i<=n;i++) while(true){ for(int j=1;j<=n;j++) vx[j]=false; for(int j=1;j<=m;j++) vy[j]=false; if(find(i)) break; else renew(); } } int main() { read(n);read(m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(f[i][j]); pra(); km(); int ans=0; for(int i=1;i<=n;i++) ans+=f[i][pre2[i]]; printf("%d\n",ans); return 0; }
时间: 2024-11-06 07:18:13