牛客多校第五场 E room 二分图匹配 KM算法模板
链接:https://www.nowcoder.com/acm/contest/143/E
来源:牛客网
Nowcoder University has 4n students and n dormitories ( Four students per dormitory). Students numbered from 1 to 4n.
And in the first year, the i-th dormitory 's students are (x1[i],x2[i],x3[i],x4[i]), now in the second year, Students need to decide who to live with.
In the second year, you get n tables such as (y1,y2,y3,y4) denote these four students want to live together.
Now you need to decide which dormitory everyone lives in to minimize the number of students who change dormitory.
输入描述:
- The first line has one integer n.
- Then there are n lines, each line has four integers (x1,x2,x3,x4) denote these four students live together in the first year
- Then there are n lines, each line has four integers (y1,y2,y3,y4) denote these four students want to live together in the second year
输出描述:
- Output the least number of students need to change dormitory.
输入例子:
- 2
- 1 2 3 4
- 5 6 7 8
- 4 6 7 8
- 1 2 3 5
输出例子:
- 2
-->
备注:
- 1<=n<=100
- 1<=x1,x2,x3,x4,y1,y2,y3,y4<=4n
- It's guaranteed that no student will live in more than one dormitories.
- 题意:第一年是学校安排宿舍,1-4*n按标号分在一起,第二年学生自由组队组成新寝室,问怎样分配可以在满足学生自由组队的情况下变动学生最少
分析:我们可以将第一年和第二年的寝室看成一个个点,然后我们要求的就是在满足学生自由组队的情况下尽量让变动学生小的寝室匹配在一起
将第一年和第二年寝室人的相同数看成是两个寝室的好感度,然后我要求的就是好感度最大的情况下的二分图匹配,直接套模板就行
AC代码:
- #include<cstdio>
- #include<cstring>
- #include<string>
- #include<iostream>
- #include<algorithm>
- #include<cmath>
- using namespace std ;
- const int maxn = 100 + 20 ;
- const int MAXN = 100+20;
- const int INF = 0x3f3f3f3f;
- int love[MAXN][MAXN]; // 记录每个妹子和每个男生的好感度
- int ex_girl[MAXN]; // 每个妹子的期望值
- int ex_boy[MAXN]; // 每个男生的期望值
- bool vis_girl[MAXN]; // 记录每一轮匹配匹配过的女生
- bool vis_boy[MAXN]; // 记录每一轮匹配匹配过的男生
- int match[MAXN]; // 记录每个男生匹配到的妹子 如果没有则为-1
- int slack[MAXN]; // 记录每个汉子如果能被妹子倾心最少还需要多少期望值
- int N;
- int vis[4*maxn] ;
- struct node {
- int a ;
- int b ;
- int c ;
- int d ;
- }e[maxn << 2];
- bool dfs(int girl) {
- vis_girl[girl] = true;
- for (int boy = 0; boy < N; ++boy) {
- if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次
- int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];
- if (gap == 0) { // 如果符合要求
- vis_boy[boy] = true;
- if (match[boy] == -1 || dfs( match[boy] )) { // 找到一个没有匹配的男生 或者该男生的妹子可以找到其他人
- match[boy] = girl;
- return true;
- }
- } else {
- slack[boy] = min(slack[boy], gap); // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸
- }
- }
- return false;
- }
- int KM() {
- memset(match, -1, sizeof match); // 初始每个男生都没有匹配的女生
- memset(ex_boy, 0, sizeof ex_boy); // 初始每个男生的期望值为0
- // 每个女生的初始期望值是与她相连的男生最大的好感度
- for (int i = 0; i < N; ++i) {
- ex_girl[i] = love[i][0];
- for (int j = 1; j < N; ++j) {
- ex_girl[i] = max(ex_girl[i], love[i][j]);
- }
- }
- // 尝试为每一个女生解决归宿问题
- for (int i = 0; i < N; ++i) {
- fill(slack, slack + N, INF); // 因为要取最小值 初始化为无穷大
- while (1) {
- // 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止
- // 记录每轮匹配中男生女生是否被尝试匹配过
- memset(vis_girl, false, sizeof vis_girl);
- memset(vis_boy, false, sizeof vis_boy);
- if (dfs(i)) break; // 找到归宿 退出
- // 如果不能找到 就降低期望值
- // 最小可降低的期望值
- int d = INF;
- for (int j = 0; j < N; ++j)
- if (!vis_boy[j]) d = min(d, slack[j]);
- for (int j = 0; j < N; ++j) {
- // 所有访问过的女生降低期望值
- if (vis_girl[j]) ex_girl[j] -= d;
- // 所有访问过的男生增加期望值
- if (vis_boy[j]) ex_boy[j] += d;
- // 没有访问过的boy 因为girl们的期望值降低,距离得到女生倾心又进了一步!
- else slack[j] -= d;
- }
- }
- }
- // 匹配完成 求出所有配对的好感度的和
- int res = 0;
- for (int i = 0; i < N; ++i)
- res += love[ match[i] ][i];
- return res;
- }
- int main() {
- while(scanf("%d",&N) != EOF) {
- memset(vis,0,sizeof(vis)) ;
- for(int i = 0 ; i < 2*N ; i ++) {
- scanf("%d %d %d %d",&e[i].a,&e[i].b,&e[i].c,&e[i].d) ;
- }
- for(int i = 0 ; i < N ; i ++) {
- vis[e[i].a] = 1 ; vis[e[i].b] = 1 ;
- vis[e[i].c] = 1 ; vis[e[i].d] = 1 ;
- for(int j = N ; j < 2*N ; j ++) {
- int pnum = 0 ;
- if(vis[e[j].a]) pnum ++ ;
- if(vis[e[j].b]) pnum ++ ;
- if(vis[e[j].c]) pnum ++ ;
- if(vis[e[j].d]) pnum ++ ;
- love[i][j - N] = pnum ; //第一年寝室和第二年寝室的匹配度
- }
- vis[e[i].a] = 0 ; vis[e[i].b] = 0 ;
- vis[e[i].c] = 0 ; vis[e[i].d] = 0 ;
- }
- printf("%d\n",4*N - KM()) ;
- }
- return 0 ;
- }
牛客多校第五场 E room 二分图匹配 KM算法模板的更多相关文章
- 牛客多校第五场 F take
链接:https://www.nowcoder.com/acm/contest/143/F来源:牛客网 题目描述 Kanade has n boxes , the i-th box has p[i] ...
- 牛客多校第五场 J:Plan
链接:https://www.nowcoder.com/acm/contest/143/J 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524 ...
- 牛客多校第五场-D-inv
链接:https://www.nowcoder.com/acm/contest/143/D来源:牛客网 题目描述 Kanade has an even number n and a permutati ...
- 牛客多校第五场 F take 期望转化成单独事件概率(模板) 树状数组
链接:https://www.nowcoder.com/acm/contest/143/F来源:牛客网 Kanade has n boxes , the i-th box has p[i] proba ...
- 牛客多校第六场 C Generation I 组合数学 阶乘逆元模板
链接:https://www.nowcoder.com/acm/contest/144/C来源:牛客网 Oak is given N empty and non-repeatable sets whi ...
- 字符串dp——牛客多校第五场G
比赛的时候脑瘫了没想出来..打多校以来最自闭的一场 显然从s中选择大于m个数组成的数必然比t大,所以只要dp求出从s中选择m个数大于t的方案数 官方题解是反着往前推,想了下反着推的确简单,因为高位的数 ...
- 【魔改】树状数组 牛客多校第五场I vcd 几何+阅读理解
https://www.nowcoder.com/acm/contest/143/I vc-dimension 题解:分三种情况,组合数学算一下,其中一种要用树状数组维护 技巧(来自UESTC):1. ...
- 2018牛客多校第五场 H.subseq
题意: 给出a数组的排列.求出字典序第k小的b数组的排列,满足1<=bi<=n,bi<bi+1,a[b[i]]<a[b[i+1]],m>0. 题解: 用树状数组倒着求出以 ...
- 2018牛客多校第五场 E.room
题意: 一共有n个宿舍,每个宿舍有4个人.给出第一年的人员分布和第二年的人员分布,问至少有多少人需要移动. 题解: 对于第一年的每个宿舍,向今年的每种组合连边.流量为1,费用为(4 - 组合中已在该宿 ...
随机推荐
- Scala的常用小技巧
1."RichString.java".stripSuffix(".java") == "RichString" "http:// ...
- Ubuntu 系统如何用pycharm开发python—OpenCV
- FormLayout and FormData
FormLayout通过为小窗口部件创建四边的Form附加值(attachment)来进行工作,并且把这些Form附加值存储在布局数据中.一个附加值让一个小窗口部件指定的一边粘贴(attach)到父C ...
- FTP服务端部署
FTP服务端搭建(本地用户登入:使用本地用户和密码登入)1.文件配置:vsftpd.conf: 主配置文件ftpusers: 指定哪些用户不能访问FTP服务器user_list: 指定的用户是否可以访 ...
- Java——集合类
1.容器的打印 import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import jav ...
- 如何在GitHub上删除自己的项目?
话不多说,直奔主题~ 1.打开GitHub,在主页左边有自己写的库. 2.拿删除第二个库wlh-hub/vue-zsgc为例,点击它,进入下面页面. 3.在导航栏一栏中,找到settings,并点击. ...
- 《机器学习基石》---VC维
1 VC维的定义 VC维其实就是第一个break point的之前的样本容量.标准定义是:对一个假设空间,如果存在N个样本能够被假设空间中的h按所有可能的2的N次方种形式分开,则称该假设空间能够把N个 ...
- java优雅注释原则和代码格式列举
一.java的三种注释类型 单行注释:// ...... 块注释:/* ...... */ 文档注释:/** ...... */ 二.指导原则 注释不能美化糟糕的代码,碰到糟糕的代码就重新写吧. 用代 ...
- Elasticsearch由浅入深(一)
什么是Elasticsearch 什么是搜索 百度:我们比如说想找寻任何的信息的时候,就会上百度去搜索一下,比如说找一部自己喜欢的电影,或者说找一本喜欢的书,或者找一条感兴趣的新闻(提到搜索的第一印象 ...
- 并发编程 Semaphore的使用和详解
类Semaphore的基本使用 Semaphore的作用:限制线程并发的数量 课外话题[多线程的同步概念]:其实就是排着队去执行一个任务,执行任务是一个一个的执行,这样的优点是有助于程序逻辑的正确性, ...