首页 > 编程语言 >匈牙利算法

匈牙利算法

时间:2024-01-20 17:01:23浏览次数:25  
标签:奇数 匈牙利 素数 偶数 算法 配对 伴侣

描述

若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的N(N为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。

输入描述:

输入说明

1 输入一个正偶数n

2 输入n个整数

注意:数据可能有多组

输出描述:

求得的“最佳方案”组成“素数伴侣”的对数。

示例:

输入:

4

2 5 6 13

2

3 6

输出:

2

0

解法

重点是

  • 如何判断是素数?
  • 如何判断偶数?
  • 如何判断奇数?
  • 采用二分图、匈牙利算法查找最优组合。

匈牙利算法

匈牙利算法是一种在多项式时间内求解任务分配问题的组合优化算法,并推动了后来的原始对偶方法(英语:primal-dual methods)。美国数学家哈罗德·库恩(英语:Harold Kuhn)于1955年提出该算法。此算法之所以被称作匈牙利算法,是因为算法很大一部分是基于以前匈牙利数学家Dénes Kőnig和Jenő Egerváry的工作之上创建起来的。

匈牙利算法主要用于解决一些与二分图匹配有关的问题,所以我们先来了解一下二分图。

二分图

那什么是二分图呢?就是能分成两组,X,Y。其中,X上的点不能相互连通,只能连去Y中的点,同理,Y中的点不能相互连通,只能连去X中的点。这样,就叫做二分图。

下图是典型的二分图。

匈牙利算法_匈牙利算法

可以看到,在上面的二分图中,每条边的端点都分别处于点集X和Y中。匈牙利算法主要用来解决两个问题:求二分图的最大匹配数和最小点覆盖数。

最大匹配数

本题的“素数伴侣”本质就是用二分图的最大匹配数来求解。假设奇数是在X数组,偶数在Y数组,题目就转为了X能连上Y最多的组合。

为了能好的理解题意,我们把奇数当做是男生(Boys),偶数当做女生(Girls):

匈牙利算法_二分图_02

Boys与Girls所有能配对的情况(奇数与偶数之和为素数),都用线连接起来了。于是题目变成了Boys与Girls能配对最多的方案。

现在我们来看看匈牙利算法是怎么运作的:

从B1看起,他可以与G2、G4配对,那就先暂时把他与G2连接。

匈牙利算法_sed_03

接下来看B2,B2也可以配对G2,但由于这时G2已经与B1配对了,那怎么办呢?我们倒回去看G2目前被配对的B1,B1有没有别的选项呢?有G4,G4还没有被安排,那我们就给B1安排上G4。

匈牙利算法_sed_04

然后观察B3,B3直接配上G1就好了,这没什么问题。至于B4,他只能配对G4,G4目前配的是B1。B1除了G4还可以选G2,但是呢,如果B1选了G2,G2的原配B2就没得选了。我们绕了一大圈,发现B4没有配对的机会了。

匈牙利算法_sed_05

所以,最终的配对结果为B1G4、B2G2、B3G1。这也是Boys与Girls能配对最多的方案。

实现

/*
  *  Copyright (c) waylau.com, 2022. All rights reserved.
 */
 
package com.waylau.nowcoder.exam.oj.huawei;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * 描述:若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,
 * 它们能应用于通信加密。现在密码学会请你设计一个程序,
 * 从已有的N(N为偶数)个正整数中挑选出若干对组成“素数伴侣”,
 * 挑选方案多种多样,例如有4个正整数:2,5,6,13,
 * 如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,
 * 能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。
 * 输入描述:输入说明
 * 1 输入一个正偶数n
 * 2 输入n个整数
 * 注意:数据可能有多组
 * 输出描述:求得的“最佳方案”组成“素数伴侣”的对数。
 * 示例:
 * 输入:
 * 4
 * 2 5 6 13
 * 输出:
 * 2
 * 输入:
 * 2
 * 3 6
 * 输出:
 * 0
 *
 * @author <a href="https://waylau.com">Way Lau</a>
 * @since 2022-08-16
 */
public class HJ028PrimeCompanion {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();

        // 输入的数字先分好为奇数、偶数两组
        List<Integer> evenList= new ArrayList<>();
        List<Integer> oddList= new ArrayList<>();
        for (int i =0; i<n;i++) {
            int j = sc.nextInt();
            if (isEven(j)) {
                evenList.add(j);
            } else {
                oddList.add(j);
            }
        }
        
        int size = evenList.size();
        int count = 0;
        
        // 已经匹配的数的伴侣
        int[] evensMatch = new int[size];

        for (Integer odd : oddList) {
            // 用于标记对应的数是否查找过
            int[] used = new int[size];

            if (find(odd, evenList, used, evensMatch)) {
                count ++;
            }
        }
        
        // 输出
        System.out.println(count);
        
        // 关闭
        sc.close();
    }
    
    // 质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数
    // 0和1既不是质数也不是合数,最小的质数是2
    private static boolean isPrime(int n) {
        if (n <= 1) {
            return false;
        } else {
            for (int i = 2; i < n; i++) {
                if (n % i == 0) {
                    return false;
                }
            }
        }

        return true;
    }

    // 偶数可以被2 整除的整数
    private static boolean isEven(int n) {
        if (n % 2 == 0) {
            return true;
        }

        return false;
    }
    
    /**
     * 找到指定数字的素数伴侣
     * 
     * @param odd
     * @param evens
     * @param used
     * @param evensMatch
     * @return
     */
    private static boolean find(int odd, List<Integer> evens, int[] used, int[] evensMatch) {
        // 遍历偶数:去检查当前传入的奇数能否与偶数哪些数匹配
        for (int i = 0; i < evens.size(); i++) {
            // 如果当前偶数与传入的奇数匹配,并且当前偶数位还没有匹配过奇数
            if (isPrime(odd + evens.get(i)) && used[i] == 0) {
                // 设置当前偶数位匹配为true,也就是 1
                used[i] = 1;
                
                // 如果第i个偶数没有伴侣
                // 或者第i个偶数原来有伴侣,并且该伴侣能够重新找到伴侣的话(这里有递归调用)
                // 则奇数odd可以设置为第i个偶数的伴侣
                // 这里采用了匈牙利算法,能让则让
                if (evensMatch[i] == 0 || find(evensMatch[i], evens, used, evensMatch)) {
                    evensMatch[i] = odd;
                    return true;
                }
            }
        }
        
        // 遍历完偶数都没有可以与传入奇数做伴侣的,该奇数只没有配对了
        return false;
    }

}


标签:奇数,匈牙利,素数,偶数,算法,配对,伴侣
From: https://blog.51cto.com/u_15590807/9345852

相关文章

  • 马拉车算法
    马拉车算法chars[maxn],ss[maxn];intp[maxn];intlen,center;intcnt=1;voidinit(){memset(s,0,sizeofs);cnt=1,s[0]='@';intlen=strlen(ss);for(inti=0;i<len;i++){s[cnt++]='#';s[cnt++]=ss......
  • 算法-数组
    1.二分查找(LeetCode704)题目:给定一个n个元素有序的(升序)整型数组nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否则返回-1。输入:nums=[-1,0,3,5,9,12],target=9输出:4解释:9出现在nums中并且下标为4......
  • 贪心算法练习
    问题描述:设有n个正整数,将他们连接成一排,组成一个最大的多位整数。例如:n=4时,4个整数21,8,901,6连成的最大整数为:9018621。贪心选择策略:(1)将所有数字转化为字符串形式。(2)将所有字符串按照长度从大到小排序。如果长度相同,则按照字典序从大到小排序。(3)将排序后的字符......
  • 算法模板 v1.3.1.20240120
    算法模板v1.1.1.20240115:之前的历史版本已经不可寻,创建了第一份算法模板。v1.2.1.20240116:删除“编译”-“手动开栈”与“编译”-“手动开O优化”;将“编译”-“CF模板”中的第20行代码cin>>T;注释;删除“读写”及其目录下的内容;删除“图论”-“欧拉图”-“混合图”;删除“图论”-......
  • PacBio长read纠错算法的研究
    PacBio长read纠错算法的研究随着第三代测序技术的快速发展,长read测序技术的出现使得我们可以更好地理解基因组的结构和功能。PacBio是一种常用的长read测序技术,但是由于其测序错误率较高,需要进行纠错以提高准确性。本文将介绍PacBio长read纠错算法的研究进展。PacBio长read纠错......
  • 2024/1/19 算法笔记
    题目1:最大公约数的延伸问题P1414又是毕业季II-洛谷|计算机科学教育新生态(luogu.com.cn)题目上提及了最大公约数,但是解答却没有直接使用最大公约数doge题目意思是给定n个数,再给定一个k,往这n个数中取k个,求这k个数的最大公约数是多少?然后题目的要求是k的取值为1到n全部取......
  • 吴师兄学算法day08 贪心 605. 种花问题
    题目:605.种花问题易错点:没想出来,借鉴了灵山的代码的思路,强行种花。我喜欢这个思路。感觉有点像设置哨兵那样的。 我的代码:classSolution:defcanPlaceFlowers(self,flowerbed:List[int],n:int)->bool:#修改数组,每次都种花,#凑够3个0......
  • 吴师兄学算法day08 贪心 860. 柠檬水找零
    题目:860.柠檬水找零易错点:我写的是ifesle哈哈,第一次还写错了。i==20的时候,5元只找了1张。哈哈哈.应该找3张 我的代码:classSolution:deflemonadeChange(self,bills:List[int])->bool:dic={5:0,10:0,20:0}foriinbills:......
  • MD4(SHA-1,SM3)算法的实现
     一、实验目的深度理解MD4(SHA-1,SM3)算法的工作原理,理解单向散列函数的应用,体会区块链挖矿的难度系数、加深对单向散列函数性质的理解。二、实验器材pycharm+python3.11三、实验内容1.实验要求:自己配置python环境,编写MD4(SHA-1,SM3)算法实现程序,运行MD4(SHA-1,SM3)程序,演......
  • 吴师兄学算法day08 贪心 134. 加油站
    题目:134.加油站理解难点:理解比较难,就是遍历1遍,尽可能找局部满足要求的。如果总油耗满足要求。那局部油耗找的出发点就是对的。遍历的时候,因为答案唯一,要么就满足要求,要么不满足要求。而<0证明之前的都不满足要求,满足要求的一定在后面。这题还是个环,环这里有点没太理解。环......