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 ;
     } 
    

      

    彼时当年少,莫负好时光。
  • 相关阅读:
    window.location.Reload()和window.location.href 区别
    PHP substr(),mb_substr()及mb_strcut的区别和用法
    jstree节点展开设置
    关于Jquery中ajax方法data参数用法
    HTML相对路径(Relative Path)和绝对路径(Absolute Path)
    Win32基础编程了解窗口类
    Visual C++ ActiveX 开发指南:第一章 什么是ActiveX
    分粥
    蛙蛙推荐:ASP实现自定义标签模板
    蛙蛙请教:如何利用委托实现多个方法同时调用.
  • 原文地址:https://www.cnblogs.com/l609929321/p/9412234.html
Copyright © 2011-2022 走看看