题解 | #素数伴侣#

素数伴侣

http://www.nowcoder.com/practice/b9eae162e02f4f928eac37d7699b352e

题目的主要信息:

  • 若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”。
  • 我们需要从一组数中,找出最多对的素数伴侣。

方法一:匈牙利算法

偶数+偶数=偶数,必不是素数,因此素数只能是奇数+偶数。我们把输入的这一组数分成奇数和偶数,就得到了二分图,在这两组之间用匈牙利算法作匹配。

  1. 首先我们遍历一遍所有数字,建立他们之间所有可能的联系,便于后面的调整。接下来开始找最优连接方案。
  2. 每次取奇数p,遍历偶数,判断是否能和奇数组成素数伴侣,如果偶数q没有和别人结成伴侣则建立p和q之间的关系;如果这个偶数q已经和别的奇数k结成伴侣,那么递归查找k的下一位能建立关系的偶数,如果找到了p和q建立关系,如果没有找到,则不改变偶数q和奇数k的关系。

匈牙利算法如下图例: alt

具体做法:

#include <iostream>
#include<vector>
using namespace std;
bool isprime(int i)//判断是否为素数
{
    for(int j=2;j*j<=i;j++)
    {
        if(i%j==0)
            return false;
    }
    return true;
}
bool find(const int & n,vector<vector<bool>> &map,vector<int>& match,vector<bool>&visit)
{
   for (int i = 0; i < match.size(); i++)
    {
        if (!visit[i] && map[i][n])//当前偶数未被访问过并且能和奇数n是素数伴侣
        {
            visit[i] = true;
            if (match[i] == -1 || find(match[i], map, match, visit))//当前偶数没有匹配或能给被抛弃的奇数找到新的偶数
            {
                match[i] = n;//建立偶数和奇数之间的连接
                return true;
            }
        }
    }
    return false;
}
int main()
{
    int n=0;
    while(cin>>n)
    {
        int k=0;//读取数据
        vector<int> even;
        vector<int> odd;
        int count=0;//匹配对数
        while(n--){//逐个输入按奇偶分类
            cin>>k;
            if(k%2==0){
                odd.push_back(k);
            }else{
                even.push_back(k);
            }
        }
        if(odd.empty()||even.empty()){//奇数或偶数为空则不会有素数伴侣
            cout<<count<<endl;
            continue;
        }
        vector<vector<bool>> map(even.size(),vector<bool>(odd.size(),false));
        for(int i=0;i<even.size();i++)//建立关系图,找出所有可能的连接
        {
            for(int j=0;j<odd.size();j++){
                if(isprime(even[i]+odd[j])){
                    map[i][j]=true;
                }
            }
        }
        vector<int> match(even.size(),-1);
        for (int i = 0; i < odd.size(); i++){
            vector<bool> visit(even.size(), false);//建立在当前奇数下对偶数的访问情况
            if (find(i, map, match, visit))
            {
                count++;
            }
        }
        cout << count << endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(mn2)O(mn^2),其中m为奇数个数,n为偶数个数,时间复杂度为O(m)O(m)for循环里嵌套着递归O(n2)O(n^2)
  • 空间复杂度:O(mn)O(mn),需要建立奇数和偶数之间连接表。

方法二:

方法二也是匈牙利算法,区别在于方法二去掉了了存储偶数和奇数之间关系的图,减少了空间,但是提高了时间复杂度,每次find函数递归遍历的时候都需要重新判断当前两个数是否为素数伴侣。

具体做法:

#include <iostream>
#include<vector>
using namespace std;
bool isprime(int i)//判断是否为素数
{
    for(int j=2;j*j<=i;j++)
    {
        if(i%j==0)
            return false;
    }
    return true;
}
bool find(const int & n,vector<int> &even,vector<int>& match,vector<bool>&visit)
{
   for (int i = 0; i < even.size(); i++)
    {
        if (!visit[i] && isprime(even[i]+n))//当前偶数未被访问过并且能和奇数n是素数伴侣
        {
            visit[i] = true;
            if (match[i] == -1 || find(match[i], even, match, visit))//当前偶数没有匹配或能给被抛弃的奇数找到新的偶数
            {
                match[i] = n;//建立偶数和奇数之间的连接
                return true;
            }
        }
    }
    return false;
}
int main()
{
    int n=0;
    while(cin>>n)
    {
        int k=0;//读取数据
        vector<int> even;
        vector<int> odd;
        int count=0;//匹配对数
        while(n--){//逐个输入按奇偶分类
            cin>>k;
            if(k%2==0){
                odd.push_back(k);
            }else{
                even.push_back(k);
            }
        }
        if(odd.empty()||even.empty()){//奇数或偶数为空则不会有素数伴侣
            cout<<count<<endl;
            continue;
        }
        vector<int> match(even.size(),-1);
        for (int i = 0; i < odd.size(); i++){
            vector<bool> visit(even.size(), false);//建立在当前奇数下对偶数的访问情况
            if (find(odd[i], even, match, visit))
            {
                count++;
            }
        }
        cout << count << endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(m(kn)2)O(m(kn)^2),k为判断是否为素数的时间复杂度。
  • 空间复杂度:O(1)O(1)
全部评论
奇数和偶数是不是反了
点赞 回复 分享
发布于 2023-08-14 22:25 北京
建立一个60000 以内的素数表,用空间换时间。
点赞 回复 分享
发布于 2022-07-10 14:25

相关推荐

2025-11-27 14:21
同济大学 Java
卢来猴祖:给了这薪资关键拿不了几个月就给你踹了呀
点赞 评论 收藏
分享
2025-12-02 02:15
门头沟学院
最近菊厂陆续开了,极力劝退那些拿13级的985硕士,就13级那么点儿薪资,一线城市每个月到手1.8/7/6w,租房2k还是破烂,吃饭2k还是预制菜,买个1k衣服都是聚酯纤维破塑料,稍微出去浪一浪,能留1w就是万岁,要是再有个啥都想买的对象,一线工作一年难存10w。隔壁工地混泥土,钳工,焊工一天800+,还包吃包住。读书18年到985硕士出来就为了进厂螺丝工?还不如从8岁童工开始干活,别人读书完了你工龄18+,混不上领导也是个小头头了。当然专科进来正式工,od都行,一般本科进来13级也OK,毕竟22岁年纪摆在那个地方还不需要太花钱。读硕博的基本26岁,工作两年就要结婚的,兜里没几个崽,连彩礼都要信用贷。菊厂离职的不少,毕竟正常没人受得了9116(梗:再来一次911刷6)。为啥这时候劝?因为刚下班,因为国考刚完,省考下周,就是可惜选调只有当年应届能报。现在回想能拍断大腿。应届生真实好身份,错过这一次,选调,考公,考编,当老师,进医院,研究所,高校,央国企,基本都无缘了,就连报名资格都被剥夺了,可谓是被党和国家遗弃的废材,统称“社会上的”,扔到社会去流浪,被用坏了就扔医院,长期超负载使用,零件修不好基本可以扔火里回炉重造了。体制内奉行找体制内的,都是党和国家选的人才,智力不差,样貌不丑,身材端正,收入稳定,安居房政策福利待遇也OK。因公出行都是报销,周末顺带“游山玩水“,这种体制内单身资源但凡想找对象,去社会上随便吆喝一声都排队。观察一下,基本没什么公务员在相亲,因为早就被邻里邻居抢光了。
哈哈哈,你是老六:就这不去的人大把人干呢,现在不缺人干活,你不干大把干呢,还有那个说农民工赚钱的,那个800+我估计肯定也就那一段时间,哪有这么赚钱,还是一句话,要想存下钱必须花销极低,能省的就不花钱,工资要高点
点赞 评论 收藏
分享
评论
8
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务