P1559 運動員最佳匹配問題
阿新 • • 發佈:2017-09-23
一行 time cst false ios memset love turn 對組
洛谷——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();} returnx*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; }
P1559 運動員最佳匹配問題