2023-03-25:若两个正整数的和为素数,则这两个正整数称之为"素数伴侣"。
给定N(偶数)个正整数中挑选出若干对,组成"素数伴侣",
例如有4个正整数:2,5,6,13,
如果将5和6分为一组的话,只能得到一组"素数伴侣",
如果将2和5、6和13编组,将得到两组"素数伴侣",
这是得到"素数伴侣"最多的划分方案。
输入:
有一个正偶数 n ,表示待挑选的自然数的个数。后面给出 n 个具体的数字。
输出:
输出一个整数 K ,表示最多能找出几对"素数伴侣"。
数据范围: 1 <= n <= 100, 2 <= val <= 30000。
来自华为。

答案2023-03-05:

用二分图最大匹配来解决。具体步骤如下:

将所有数字看作二分图的左右两部分节点,如果两个节点的和是一个素数,则在它们之间连接一条边。

使用 KM 算法求解二分图的最大匹配。最大匹配的结果就是最多能找到多少对“素数伴侣”。

这里需要注意的是,KM算法的时间复杂度为 O(n^3),但本题数据范围比较小,因此可以通过。

rust代码如下:

// 构造邻接矩阵
fn matrix(arr: &[i32], n: usize) -> Vec<Vec<i32>> {
// 判断是否是素数的函数
let is_prime = |num| (2..(num as f64).sqrt() as i32 + 1).all(|i| num % i != 0);
let mut ans = vec![vec![0; n]; n];
for i in 0..n {
for j in 0..n {
ans[i][j] = if is_prime(arr[i] + arr[j]) { 1 } else { 0 };
}
}
ans
} // KM算法实现求解最大匹配
fn km(graph: &[Vec<i32>]) -> i32 {
let n = graph.len();
let invalid = i32::MAX;
let mut match_ = vec![-1; n]; // 记录匹配情况的数组,初始值为-1表示没有匹配
let mut lx = vec![-invalid; n]; // 左部点的标号
let mut ly = vec![0; n]; // 右部点的标号
let mut x = vec![false; n]; // 记录左部点是否被访问
let mut y = vec![false; n]; // 记录右部点是否被访问
let mut slack = vec![invalid; n]; // 记录松弛量
// 初始化左部点的标号为与之相连的右部点的边权的最大值
for i in 0..n {
for j in 0..n {
lx[i] = lx[i].max(graph[i][j]);
}
}
// 在未匹配的情况下,进行增广
while let Some(from) = (0..n).find(|i| match_[*i] == -1) {
slack.fill(invalid); // 初始化松弛量为无穷大
x.fill(false); // 初始化左部点为未访问
y.fill(false); // 初始化右部点为未访问
// 在当前的未匹配节点进行增广
while !dfs(
from,
&mut x,
&mut y,
&lx,
&ly,
&mut match_,
&mut slack,
graph,
) {
// 如果无法找到增广路,则更新标号
let d = slack
.iter()
.enumerate()
.filter(|&(i, &s)| !y[i] && s != invalid)
.map(|(i, _)| i)
.min()
.unwrap();
for i in 0..n {
if x[i] {
lx[i] -= slack[d];
}
if y[i] {
ly[i] += slack[d];
}
}
x.fill(false);
y.fill(false);
}
}
// 计算所有边的权值和
lx.iter().sum::<i32>() + ly.iter().sum::<i32>()
} // DFS函数实现增广
fn dfs(
from: usize,
x: &mut [bool],
y: &mut [bool],
lx: &[i32],
ly: &[i32],
match_: &mut [i32],
slack: &mut [i32],
graph: &[Vec<i32>],
) -> bool {
let n = graph.len();
x[from] = true; // 记录左部点为已访问
for to in 0..n {
if !y[to] {
// 如果右部点没有被访问
let d = lx[from] + ly[to] - graph[from][to]; // 计算松弛量
if d != 0 {
// 如果松弛量不为0,则更新松弛量
slack[to] = slack[to].min(d);
} else {
// 如果松弛量为0,则进行增广
y[to] = true; // 标记右部点为已访问
if match_[to] == -1 || dfs(match_[to] as usize, x, y, lx, ly, match_, slack, graph)
{
// 如果当前右部点没有匹配,或者能够寻找到增广路,则进行匹配,并返回true
match_[to] = from as i32;
return true;
}
}
}
}
false // 没有找到增广路,返回false
} // 主函数
fn main() {
// 示例数据1
println!("{}", km(&matrix(&[2, 5, 6, 13], 4)) / 2); // 输出结果为2 // 示例数据2
println!("{}", km(&matrix(&[3, 6], 2)) / 2); // 输出结果为0
}

2023-03-25:若两个正整数的和为素数,则这两个正整数称之为“素数伴侣“。 给定N(偶数)个正整数中挑选出若干对,组成“素数伴侣“, 例如有4个正整数:2,5,6,13, 如果将5和6分为一组的的更多相关文章

  1. [2019.03.25]Linux中的查找

    TMUX天下第一 全世界所有用CLI Linux的人都应该用TMUX,我爱它! ======================== 以下是正文 ======================== Linu ...

  2. Java基础-多线程编程-1.随便选择两个城市作为预选旅游目标。实现两个独立的线程分别显示10次城市名,每次显示后休眠一段随机时间(1000ms以内),哪个先显示完毕,就决定去哪个城市。分别用Runnable接口和Thread类实现。

    1.随便选择两个城市作为预选旅游目标.实现两个独立的线程分别显示10次城市名,每次显示后休眠一段随机时间(1000ms以内),哪个先显示完毕,就决定去哪个城市.分别用Runnable接口和Thread ...

  3. @有两个含义:1,在参数里,以表明该变量为伪参数 ,在本例中下文里将用@name变量代入当前代码中2,在字串中,@的意思就是后面的字串以它原本的含义显示,如果不

    @有两个含义:1,在参数里,以表明该变量为伪参数 ,在本例中下文里将用@name变量代入当前代码中 2,在字串中,@的意思就是后面的字串以它原本的含义显示,如果不加@那么需要用一些转义符\来显示一些特 ...

  4. 有两个指针pa,pb分别指向有两个数,a,b,请写一个函数交换两个指针的指向,也就是让pa指向b,让pb指向a

    题目:有两个指针pa,pb分别指向有两个数,a,b,请写一个函数交换两个指针的指向,也就是让pa指向b,让pb指向a,具体实现如下: #include<stdlib.h> #include ...

  5. 如何从两个List中筛选出相同的值

    问题 现有社保卡和身份证若干,想要匹配筛选出一一对应的社保卡和身份证. 转换为List socialList,和List idList,从二者中找出匹配的社保卡. 模型 创建社保卡类 /** * @a ...

  6. 在编写wpf界面时候中出现如下错误: 类型引用不明确。至少有两个名称空间(“System.Windows”和“System.Windows”)中已出现名为“VisualStateManager”的类型。请考虑调整程序集 XmlnsDefinition 特性。

    wpf中类型引用不明确.至少有两个名称空间(“System.Windows”和“System.Windows”)中已出现名为“VisualState 你是不是用了WPFToolKit?如果是的,那原因 ...

  7. 一个范围的两个数进行数位的累加,实现对两个数num1和num2的数位和相加

    对一个范围的两个数进行数位的累加,例如有两个数 15,19则 他们的数位和应该为: 1+5+1+6+1+7+1+8+1+9,结果为40. 测试说明 样例1 输入:1519 输出: 40 以下是不同方法 ...

  8. 合并两个数组并去重(ES5和ES6两种方式实现)

    合并两个数组并去重(ES5和ES6两种方式实现) ES6实现方式 let arr1 = [1, 1, 2, 3, 6, 9, 5, 5, 4] let arr2 = [1, 2, 5, 4, 9, 7 ...

  9. hdu5795 A Simple Nim 求nim求法,打表找sg值规律 给定n堆石子,每堆有若干石子,两个人轮流操作,每次操作可以选择任意一堆取走任意个石子(不可以为空) 或者选择一堆,把它分成三堆,每堆不为空。求先手必胜,还是后手必胜。

    /** 题目:A Simple Nim 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5795 题意:给定n堆石子,每堆有若干石子,两个人轮流操作,每次操作 ...

  10. 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数

    今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...

随机推荐

  1. OSPF与ISIS比较

  2. ClassLoader 双亲委派

    一个程序有一个默认的appClassLoader.类不是由被调用者也不是被自身加载的,正常情况下是被默认的AppClassLoader加载的. System.out.println(test3.cla ...

  3. 使用VSCode调试C#时,Console.ReadLine()弹出命令框调试

    原文链接:https://blog.csdn.net/qq_29503199/article/details/88351498   要在调试时读取输入,可以在 launch.json 中使用配置中的 ...

  4. SpringBoot整合RocketMQ案例实战

    一.概念 rocketMQ是一款典型的分布式架构下的中间件产品,使用异步通信方式和发布订阅的消息传输模型,具备异步通信的优势,系统拓扑简单,上下游耦合较弱,主要应用于异步解耦,流量削峰填谷等场景 二. ...

  5. PHP 计算机码、位运算、运算符优先级

    计算机码 计算机在实际存储数据的时候,是采用编码规则的(二进制编码) 计算机码存储的过程: 原码.反码和补码,数值最左边一位用来充当符号位:符号为正数为0,负数为1 原码:数据本身从十进制转换为二进制 ...

  6. 什么是RPA?RPA能干什么?

    一.什么是RPA什么是RPA? RPA的全称为机器人流程自动化(Robotic Process Automation),即:"机器人流程自动化",是一种智能化的企业流程管理系统.R ...

  7. HTTP 返回状态码403,404,502等不同报错原因及解决思路

    要学会看日志rpm的默认路径 /var/log/nginx/源码的默认路径 安装路径/logs/ 排错思路: 1)服务器启动失败,直接"nginx -t"测试语法   看配置文件是 ...

  8. 玩转SpringBoot原理:掌握核心技术,成为高级开发者

    本文通过编写一个自定义starter来学习springboot的底层原理,帮助我们更好的使用springboot集成第三方插件 步骤一:创建项目 步骤二:添加依赖 步骤三:创建自动配置类 步骤四:创建 ...

  9. MyBatis各个版本下载 以及 Apache Maven 安装

    推荐下面两篇文章:实测有效! MyBatis下载和环境搭建 Maven详细安装教程

  10. 原来还能这样看Java线程的状态及转换

    作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功.JAVA底层.面试.职业成长相关资料等更多精彩文章在公众号「小牛呼噜噜」 大家好,我是呼噜噜,最近一直在梳理Jav ...