KM最容易看懂的教程和参考程序
来源:互联网 发布:金融大数据分析是什么 编辑:程序博客网 时间:2024/06/15 01:48
现在有N男N女,有些男生和女生之间互相有好感,我们将其好感程度定义为好感度,我们希望把他们两两配对,并且最后希望好感度和最大。
怎么选择最优的配对方法呢?
首先,每个女生会有一个期望值,就是与她有好感度的男生中最大的好感度。男生呢,期望值为0,就是……只要有一个妹子就可以啦,不挑~~
这样,我们把每个人的期望值标出来。
接下来,开始配对。
配对方法:
我们从第一个女生开始,分别为每一个女生找对象。
每次都从第一个男生开始,选择一个男生,使男女两人的期望和要等于两人之间的好感度。
注意:每一轮匹配,每个男生只会被尝试匹配一次!
具体匹配过程:
==============为女1找对象===============
(此时无人配对成功)
根据 “男女两人的期望和要等于两人之间的好感度”的规则
女1-男1:4+0 != 3
女1-男3:4+0 == 4
所以女1选择了男3
女1找对象成功
==============为女1找对象成功============
==============为女2找对象===============
(此时女1—男3)
根据配对原则,女2选择男3
男3有主女1,女1尝试换人
我们尝试让女1去找别人
尝试失败
为女2找对象失败!
==============为女2找对象失败============
这一轮参与匹配的人有:女1,女2,男3。
怎么办???很容易想到的,这两个女生只能降低一下期望值了,降低多少呢?
任意一个参与匹配女生能换到任意一个这轮没有被选择过的男生所需要降低的最小值
比如:女1选择男1,期望值要降低1。 女2选择男1,期望值要降低1。 女2选择男2,期望值要降低2。
于是,只要期望值降低1,就有妹子可能选择其他人。所以妹子们的期望值要降低1点。
同时,刚才被抢的男生此时非常得意,因为有妹子来抢他,与是他的期望值提高了1点(就是同妹子们降低的期望值相同)。
与是期望值变成这样(当然,不参与刚才匹配过程的人期望值不变)
==============继续为女2找对象=============
(此时女1—男3)
女2选择了男1
男1还没有被配对
女2找对象成功!
==============为女2找对象成功=============
==============为女3找对象===============
(此时女1—男3,女2-男1)
女3没有可以配对的男生……
女3找对象失败
==============为女3找对象失败============
此轮只有女3参与匹配
此时应该为女3降低期望值
降低期望值1的时候,女3-男3可以配对,所以女3降低期望值1
==============继续为女3找对象============
(此时女1—男3, 女2-男1)
女3相中了男3
此时男3已经有主女1,于是女1尝试换人
女1选择男1
而男1也已经有主女2,女2尝试换人
前面说过,每一轮匹配每个男生只被匹配一次
所以女2换人失败
女3找对象再次失败
==============为女3找对象失败============
这一轮匹配相关人员:女1,女2,女3,男1,男3
此时,只要女2降低1点期望值,就能换到男2
(前面提过 只要任意一个女生能换到任意一个没有被选择过的男生所需要降低的最小值)
我们把相应人员期望值改变一下
==============还是为女3找对象============
(此时女1—男3, 女2-男1)
女3选择了男3
男3有主女1,女1尝试换人
女1换到了男1
男1已经有主女2,女2尝试换人
女2换人男2
男2无主,匹配成功!!!
==============为女3找对象成功=============
匹配成功!!!撒花~~
到此匹配全部结束
此时
女1-男1,女2-男2,女3-男3
好感度和为最大:9
虽然不停换人的过程听起来很麻烦,但其实整个是个递归的过程,实现起来比较简单。比较复杂的部分就是期望值的改变,但是可以在递归匹配的过程中顺带求出来。
#include <iostream>#include <ctime>#include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <cstdlib>#include <queue>#include <iomanip>#include <stack>using namespace std;int w[1005][1005];const int inf=(1<<20)-1;int m,n;//n左m右 int cx[1005],cy[1005];//顶标 bool usex[1005],usey[1005];//本回合使用的x,y int link[1005];//link[i]=x代表:在y图中的i与x相连 bool dfs(int u){ usex[u]=1; for(int i=1;i<=m;i++) if(!usey[i]&&cx[u]+cy[i]==w[u][i]){ usey[i]=1; if(link[i]==-1||dfs(link[i])){//注意这里要搜link[i]而不是i,因为我们只搜索x侧的,不需要搜索y侧的 link[i]=u; return 1; } }return 0;}int KM(){ memset(cy,0,sizeof(cy)); memset(cx,-1,sizeof(cx)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cx[i]=max(cx[i],w[i][j]); for(int i=1;i<=n;i++){ while(1){ int d=inf; memset(usex,0,sizeof(usex)); memset(usey,0,sizeof(usey)); if(dfs(i))break; for(int i=1;i<=n;i++) if(usex[i]) for(int j=1;j<=m;j++) if(!usey[j])d=min(d,cx[i]+cy[j]-w[i][j]); if(d==inf)return -1; for(int i=1;i<=n;i++) if(usex[i])cx[i]-=d; for(int i=1;i<=m;i++) if(usey[i])cy[i]+=d; } } int ans=0; for(int i=1;i<=m;i++){ if(~link[i])ans+=w[link[i]][i]; } return ans; }int main (){ while(~scanf("%d%d",&n,&m)){ memset(w,0,sizeof(w)); memset(link,-1,sizeof(link)); int a,b,c; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&w[i][j]); printf("%d\n",KM()); } return 0;}
- KM最容易看懂的教程和参考程序
- SSM整合 最容易看懂的
- 最容易看懂的动态规划
- 最容易看懂的红黑树演变
- 最容易理解的快速排序方法和程序
- Handler详解(最容易看懂,最容易理解)
- Handler详解(最容易看懂,最容易理解)
- 最容易上手的EJB教程
- 最容易的第一个WINDOWS程序
- 容易看懂的才是好代码
- 容易看懂的才是好代码
- 写java程序最容易犯的21种错误
- 编写Java程序最容易犯的21种错误
- 写java程序最容易犯的21种错误
- 写java程序最容易犯的21种错误
- 编写Java程序最容易犯的21种错误
- 编写Java程序最容易犯的21种错误
- 写java程序最容易犯的21种错误
- Android—ViewPager+布局xml(View)
- Python文件/文件夹操作大全
- 赛马问题
- 利用定时器定时发送邮箱邮件
- 如何从参与开源项目的过程中获取自信
- KM最容易看懂的教程和参考程序
- ijkplayer视频播放器源码分析(android)
- Scut服务器创建定时器的方法
- Opencv学习之线性滤波
- 快速上手MySql && MySql GUI工具 SQLyog Community (6)
- 关于oc的#pragma mark
- RK3288 平台(Android 5.1)+ PN548 调试流水账(二、Kconfig & Makefile 配置)
- Spring-AOP概论
- Android Sqlite的介绍及使用