牛客网 素数伴侣(二分图最大匹配,匈牙利算法)

题目链接:https://www.nowcoder.com/questionTerminal/b9eae162e02f4f928eac37d7699b352e

解题方案:2<=x,y<=30000,则4<=x+y<=60000,这个范围内只有奇数才有可能成为素数,而只有奇数+偶数=奇数,所以可以将n个数分成奇数和偶数两拨,然后可以相加凑成素数的则连上一条边,这样就转换成了二分图的最大匹配问题,可以用匈牙利算法。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>

using namespace std;

#define FOR(i,k,n) for(int i=k;i<n;i++)
#define FORR(i,k,n) for(int i=k;i<=n;i++)
#define scan(a) scanf("%d",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mst(a,n)  memset(a,n,sizeof(a))
#define ll long long
#define N 105
#define mod 1000000007
#define INF 0x3f3f3f3f

const double eps=1e-8;
const double pi=acos(-1.0);

int alen,blen;
int a[N],b[N],match[N],check[N],match1[N];
int g[N][N];
int ans;

bool Dfs(int u)
{
    FOR(v,0,blen)
    {
        if(g[u][v])
        {
            if(!check[v])//v不在交替路中,此时u-v一定是一条非匹配边,因为u是非匹配点
            {            //或u是匹配点且递归走匹配边过来的,而且已经将匹配边放入交替路了,而一个匹配点只会有一条匹配边
                check[v]=1;//放入交替路
                if(match[v]==-1||Dfs(match[v]))//到达未匹配点,说明此时交替路为增广路,则交换路径,并返回成功
                {                              //或者到达匹配点,此时走匹配边v-match[v],若最后找到增广路,则交换路径,并返回成功
                    match[v]=u;
                    //match1[u]=v;
                    return true;
                }
            }
        }
    }
    return false;
}

bool isPrime(int x)
{
    for(int i=2;i<=sqrt(x);i++)
        if(x%i==0) return false;
    return true;
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);

    int n;
    while(~scan(n))
    {
        alen=blen=0;
        mst(match,-1); mst(g,0);

        FOR(i,0,n)
        {
            int tmp;
            scan(tmp);
            if(tmp&1) a[alen++]=tmp;
            else b[blen++]=tmp;
        }
        FOR(i,0,alen) FOR(j,0,blen) if(isPrime(a[i]+b[j])) g[i][j]=1;
        ans=0;
        FOR(i,0,alen)
        {
            //printf("***%d\n",match1[i]);
            //此时i一定为非匹配点,因为每次Dfs返回成功的话都只会在二分图左右两边分别增加一个匹配点,增加一条匹配边
            //二分图左边增加一个点i后,Dfs检查是否可以增加一条匹配边
           mst(check,0);
            if(Dfs(i)) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

匈牙利算法中贪心思想(不断找增广路)的正确性证明:

https://liam0205.me/2016/04/03/Hungarian-algorithm-in-the-maximum-matching-problem-of-bigraph/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值