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 阅读(215) 评论(0) 编辑 收藏 举报