最小费用最大流解决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]。设计一个算法,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。

 方法:

  加超级源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;
}  
原文地址:https://www.cnblogs.com/FEIIEF/p/12242094.html