zoukankan      html  css  js  c++  java
  • 牛客多校第五场 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.

    示例1

    输入

    复制
    2
    1 2 3 4
    5 6 7 8
    4 6 7 8
    1 2 3 5

    输出

    复制
    2

    说明

    Just swap 4 and 5

    备注:

    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
    ",4*N - KM()) ; 
    	 } 
    	return 0 ;
     } 
    

      

    彼时当年少,莫负好时光。
  • 相关阅读:
    requests模块获取cookie和禁止重定向
    python 获取当前,上级,上上级路径
    jmeter正则表达提取器以及全局变量
    Linux性能监控软件netdata中文汉化版
    windows下搭建jenkins+allure+pytest
    Flask 重写wtforms验证器异常信息
    redis info 详解
    centos 安装setup命令的方法
    redis 配置
    linux 使用 vim 玩python
  • 原文地址:https://www.cnblogs.com/l609929321/p/9412234.html
Copyright © 2011-2022 走看看