前置知识 : 匈牙利算法
首先有这样一张图,求这张图的最大权完美匹配。
当然如果你不想看这些渣图的话,您可以转到 洛谷 运动员最佳匹配问题
下面我来强行解释一下KM算法
左边一群妹子找汉子,但是每个妹子都对汉字的好感度不一样,我们首先看一看每个妹子的最大好感度[期望值]是多少,同时先暂时把汉字的最大好感度[期望值]设为0
现在妹子的梦想能不能实现呢,我们来看一看
NO.1给A找汉子
这张图有一个明显的特性,就是每个妹子与让她有好感的汉子之间的边权总小于等于妹子的最大期待值。
凭着我初中数学考炸的经验,告诉你当取等的时候,你就没有辜负这个妹子的期望值
成了,不管有接下来有什么矛盾,我们去给B找汉子吧
NO.2给B找汉子
现在看起来没有什么矛盾,然后妹子C进来了
NO.3给C找妹子
貌似没有那么容易了,因为B已经和c在一起了
现在怎么办呢? 协商一下吧,C对B说:“(磨刀声)要不您换个口味吧 你我各退一步吧”
B:ook
但是汉子c看见BC这样吵架 心里顿时骄傲,于是自己的骄傲值加个1
那现在不就好办了吗。
所以这张图的最大权完美匹配就是11了
伪代码就好办了
void 匈牙利() { 判断访问妹子 遍历她的汉子们 返回 } void km() { for(每个点) //根据定义,每个点都能求到最大权 完美 匹配 的 { for(尝试n次||while 1) //这两个一个意思 { if(求到妹子汉子之间期望值之和等于边权→匈牙利算法 ) break; 刷新妹子的期望值; 刷新汉子的骄傲值; //不要忘了 每次匈牙利算法清空 vis } } }
所以上一段代码,题就是开头的 运动员最佳匹配问题
#include<iostream> #include<cmath> #include<queue> #include<cstring> #include<cstdio> #include<queue> #include<vector> #include<algorithm> using namespace std; int n,m,love[50][50],lx[50],ly[50]; int vx[50],vy[50],bd[50],tot,mmn; int dfs(int t) { if(vx[t])return 0; vx[t]=1; int i; for(i=1;i<=n;i++) { if(vy[i]) continue; int p=lx[t]+ly[i]-love[t][i]; if(!p) { vy[i]=1; if(dfs(bd[i])||!bd[i]) { bd[i]=t; return 1; } } else if(p>0) mmn=min(mmn,p); } return 0; } void km() { int i,j; for(i=1;i<=n;i++) { while(1) { mmn=0x3f3f3f3f; memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); if(dfs(i)) break; for(j=1;j<=n;j++) { if(vx[j]) lx[j]-=mmn; if(vy[j]) ly[j]+=mmn; } } } } int main() { scanf("%d",&n); int i,j; for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%d",&love[i][j]); for(i=1;i<=n;i++) for(j=1;j<=n;j++) { int t; scanf("%d",&t); love[j][i]*=t; } for(i=1;i<=n;i++) for(j=1;j<=n;j++) { lx[i]=max(love[i][j],lx[i]); } km(); for(i=1;i<=n;i++) tot+=love[bd[i]][i]; printf("%d",tot); return 0; }