最小费用最大流解决KM匹配问题
作者:互联网
题目:P1559
https://www.luogu.com.cn/problem/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]。设计一个算法,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。
$ \frac{{-b}\pm\sqrt{b^2-4ac}}{2a} $
方法:
加超级源S, 超级汇T。S向每位男运动员连容量1,费用0的边,每位女运动员向超级汇连接容量1,费用0的边,每位男运动员向女运动员连接容量1,费用为竞赛优势的边,跑最大费用最大流。用SPFA找增广路径。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=20; const int INF=0x3f3f3f3f; int q[maxn][maxn]; int p[maxn][maxn]; int w[maxn][maxn]; int n; int S,T; int dis[100]; queue<int> qe; int inqueue[100]; int pre[100]; int minflow[100]; int resflow; int res; struct Edge{ int next, from, to, remain,fi; }e[1000]; int head[100]; int en; void addEdge(int from, int to, int flow, int fi){ e[en].next=head[from]; e[en].from=from; e[en].to=to; e[en].remain=flow; e[en].fi=fi; head[from]=en; ++en; } void add(int from, int to, int flow, int fi){ addEdge(from,to,flow,fi); addEdge(to,from,0,-fi); } void spfa(){ memset(dis,128,sizeof(dis)); memset(pre,-1,sizeof(pre)); memset(minflow,0,sizeof(minflow)); minflow[S]=INF; dis[S]=0; qe.push(S); inqueue[S]=1; while(!qe.empty()){ int cur=qe.front(); qe.pop(); inqueue[cur]=0; for(int i=head[cur];i!=-1;i=e[i].next){ int v=e[i].to; int c=e[i].fi; if(e[i].remain>0 && dis[v]<dis[cur]+c){ minflow[v]=min(minflow[cur],e[i].remain); dis[v]=dis[cur]+c; pre[v]=i; if(!inqueue[v]){ inqueue[v]=1; qe.push(v); } } } } } void EK(){ while(true){ spfa(); if(pre[T]==-1) break; int v=T; while(true){ int edge=pre[v]; if(edge==-1) break; e[edge].remain-=minflow[T]; e[edge^1].remain+=minflow[T]; v=e[edge].from; } resflow+=minflow[T]; res+=minflow[T]*dis[T]; } } int main(){ memset(head,-1,sizeof(head)); res=0; resflow=0; scanf("%d", &n); for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ scanf("%d", &p[i][j]); } } for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ scanf("%d", &q[i][j]); } } for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ w[i][j]=p[i][j]*q[j][i]; } } S=0; T=2*n+1; for(int i=1;i<=n;++i){ add(S,i,1,0); add(i+n,T,1,0); } for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ add(i,j+n,1,w[i][j]); } } EK(); printf("%d", res); return 0; }
标签:qe,en,匹配,int,最小,KM,运动员,maxn,fi 来源: https://www.cnblogs.com/FEIIEF/p/12242094.html