Ek算法浅析(带权二分图)
https://www.cnblogs.com/logosG/p/logos.html
https://blog.csdn.net/chenshibo17/article/details/79933191
HDU 2255
/*
* @Author: CY__HHH
* @Date: 2019-10-23 20:09:44
* @LastEditTime: 2019-10-24 16:41:12
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstring>
#define inf (0x3f3f3f3f)
const int maxn = 305;
int Grape[maxn][maxn];
int exp_girl[maxn];
int exp_boys[maxn];
bool vis_girl[maxn],vis_boys[maxn];
int match[maxn],minExp[maxn],n;
using namespace std;
bool find(int u)
{
vis_girl[u] = true;
for(int v=0;v!=n;++v)
{
if(vis_boys[v])
continue;//只能匹配一次
int value = exp_girl[u] + exp_boys[v] - Grape[u][v];
if(!value)//符合要求
{
vis_boys[v] = true;//路径
if(match[v]==-1||find(match[v]))
{
match[v] = u;
return true;
}
}else{
minExp[v] = min(minExp[v],value);//得到路径中的左边节点的min
}
}
return false;
}
int KM()
{
memset(match,-1,sizeof(match));
memset(exp_boys,0,sizeof(exp_boys));
for(int v=0;v!=n;++v)
{
exp_girl[v] = Grape[v][0];
for(int i=1;i!=n;++i)
exp_girl[v] = max(exp_girl[v],Grape[v][i]);
}//最大期望值
for(int v=0;v!=n;++v)//为每个girl节点
{
memset(minExp,inf,sizeof(minExp));//减少最少权值能够增加边(增广路)
while(true)//如果找不到,就降低权值
{
memset(vis_girl,false,sizeof(vis_girl));
memset(vis_boys,false,sizeof(vis_boys));//记录路径
if(find(v))
break;//如果找到匹配
int mind = inf;
//因为现存的路径中无法满足匹配,所以需要从非路径中节点挑选一个减少最小的来完成(增加边)
for(int i=0;i!=n;++i)
if(!vis_boys[i])
mind = min(mind,minExp[i]);
for(int i=0;i!=n;++i)
{
if(vis_girl[i])
exp_girl[i] -= mind;
if(vis_boys[i])
exp_boys[i] += mind;
else
minExp[i] -= mind;
}
}
}
int cnt = 0;
for(int i=0;i!=n;++i)
cnt += Grape[match[i]][i];
return cnt;
}
int main()
{
while(scanf("%d",&n)==1)
{
for(int i=0;i!=n;++i)
for(int j=0;j!=n;++j)
scanf("%d",&Grape[i][j]);
printf("%d\n",KM());
}
}
不怕万人阻挡,只怕自己投降。
posted on 2019-10-24 16:48 chengyulala 阅读(242) 评论(0) 收藏 举报
浙公网安备 33010602011771号