最小费用最大流解决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

时间: 2024-11-13 06:42:07

最小费用最大流解决KM匹配问题的相关文章

HIT2739 The Chinese Postman Problem(最小费用最大流)

题目大概说给一张有向图,要从0点出发返回0点且每条边至少都要走过一次,求走的最短路程. 经典的CPP问题,解法就是加边构造出欧拉回路,一个有向图存在欧拉回路的充分必要条件是基图连通且所有点入度等于出度. 而这题,果断联想到混合图欧拉回路的做法,用最小费用最大流解决: 先只考虑所有边都只走一次,计算出各个点的出度和入度,出度不等于入度的点就需要选择几条边去改变调整它们 对于出度多的就和容量网络的汇点连容量出度-入度费用0的边,入度多的源点就向其同样地连边 对于原图中的所有边<u,v>由u向v连容

[hdu1533]二分图最大权匹配 || 最小费用最大流

题意:给一个n*m的地图,'m'表示人,'H'表示房子,求所有人都回到房子所走的距离之和的最小值(距离为曼哈顿距离). 思路:比较明显的二分图最大权匹配模型,将每个人向房子连一条边,边权为曼哈顿距离的相反数(由于是求最小,所以先取反后求最大,最后再取反回来即可),然后用KM算法跑一遍然后取反就是答案.还可以用最小费用最大流做,方法是:从源点向每个人连一条边,容量为1,费用为0,从每个房子向汇点连一条边,容量为1,费用为0,从每个人向每个房子连一条边,容量为1,费用为曼哈顿距离的值,建好图后跑一遍

hdu 3488(KM算法||最小费用最大流)

Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 2925    Accepted Submission(s): 1407 Problem Description In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000

hdoj 1533 Going Home 【最小费用最大流】【KM入门题】

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3443    Accepted Submission(s): 1763 Problem Description On a grid map there are n little men and n houses. In each unit time, every

UVA1658 Admiral 拆点法解决结点容量(路径不能有公共点,容量为1的时候) 最小费用最大流

/** 题目:UVA1658 Admiral 链接:https://vjudge.net/problem/UVA-1658 题意:lrj入门经典P375 求从s到t的两条不相交(除了s和t外,没有公共点)的路径,使得权值和最小. 思路:拆点法. 除了s,t外.把其他点都拆成两个. 例如点A,拆成A和A'.A指向A'连一条容量为1,花费为0的边. 原来指向A的,仍然指向A点. 原来A指向其他点的,由A'指向它们. 最小费用最大流求流量为2时候的最小费用即可. */ #include<iostrea

【进阶——最小费用最大流】hdu 1533 Going Home (费用流)Pacific Northwest 2004

题意: 给一个n*m的矩阵,其中由k个人和k个房子,给每个人匹配一个不同的房子,要求所有人走过的曼哈顿距离之和最短. 输入: 多组输入数据. 每组输入数据第一行是两个整型n, m,表示矩阵的长和宽. 接下来输入矩阵. 输出: 输出最短距离. 题解: 标准的最小费用最大流算法,或者用KM算法.由于这里是要学习费用流,所以使用前者. 最小费用最大流,顾名思义,就是在一个网络中,不止存在流量,每单位流量还存在一个费用.由于一个网络的最大流可能不止一种,所以,求出当前网络在流量最大的情况下的最小花费.

HDU 4862 Jump(更多的联合培训学校1)(最小费用最大流)

职务地址:pid=4862">HDU4862 最小费用流做的还是太少. 建图想不出来. . . 直接引用官方题解的话吧... 最小K路径覆盖的模型.用费用流或者KM算法解决,构造二部图,X部有N*M个节点.源点向X部每一个节点连一条边,流量1,费用0,Y部有N*M个节点,每一个节点向汇点连一条边.流量1,费用0.假设X部的节点x能够在一步之内到达Y部的节点y,那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量.流量1,再在X部添加一个新的节点,表示能够从随意节点出发K

HDU 4862 Jump(多校联合训练1)(最小费用最大流)

题目地址:HDU4862 最小费用流做的还是太少.建图想不出来... 直接引用官方题解的话吧... 最小K路径覆盖的模型,用费用流或者KM算法解决,构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,流量1,费用0,Y部有N*M个节点,每个节点向汇点连一条边,流量1,费用0,如果X部的节点x可以在一步之内到达Y部的节点y,那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量,流量1,再在X部增加一个新的节点,表示可以从任意节点出发K次,源点向其连边,费用0,流量K,这个点向

POJ 2195 地图的最小费用最大流

思路:这题刚开始看就知道是最小费用最大流了,因为求出最优嘛,而且要m,H要一一对应,所以不是二分图匹配就是最小费用最大流. 不过,刚开始还在想每个m与H之间的最小花费如何求,难道要用dfs搜索吗?这样想之后看了下题目给的时间是1000ms,然后就把dfs搜索m与H之间的最短距离排除了.然后想了想,其实尼玛太简单了,因为题目说了只能垂直与竖直的走,所以最短距离不就是两个横坐标相减与两个纵坐标相减之和嘛! 然后每对m与H之间都连边,流量为1(因为每对匹配不能重复),费用为它们之间的距离即花费:然后建