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

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
}

1679748371323.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容