题解 | #素数伴侣#

素数伴侣

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

增广路算法不叙述了,实现看代码,很详细的

// https://www.nowcoder.com/practice/b9eae162e02f4f928eac37d7699b352e
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;

const int maxn = 5 + 1e3;

int n;
int a[maxn];

int xsiz;  // 左部数量
vector<int> adj[maxn];

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

void init() {
    for (int j = 1; j <= n; ++j)  // 将集合划分为左右部,区别是奇偶性
        if (a[j] % 2) swap(a[++xsiz], a[j]);
    for (int u = 1; u <= xsiz; ++u) {
        for (int v = xsiz + 1; v <= n; ++v) {
            if (!isPrime(a[u] + a[v])) continue;  // 如果和为素数,那么添加二部图的边
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
    }
}

int match[maxn];  // match[u] = v
bool visit[maxn];

// 尝试找一条起点为 v 的增广路
bool dfs(int v) {
    if (visit[v]) return 0;
    visit[v] = 1;
    // 递归过程:通过虚边找到一条有实边的节点 u,然后递归处理 match[u]
    for (auto u : adj[v]) {
        if (match[u] == v) continue;    // 是一条实边
        if (match[u] == 0) continue;    // v 通过了虚边找到了 u,但是 u 没有实边
        if (visit[match[u]]) continue;  // u 的实边指向已搜索的 v
        if (dfs(match[u])) {
            // 找到了以 match[u] 为起点的增广路
            // 那么加上两条边仍是增广路:v-->u-->match[u]
            match[u] = v;  // 那么交换虚实边
            return true;
        }
    }

    // 尝试找一条虚边
    for (auto u : adj[v]) {
        if (match[u] == 0) {
            match[u] = v;
            return true;
        }
    }
    return false;  // 没找到
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    init();

    for (int v = xsiz + 1; v <= n; ++v) {
        memset(visit, 0, sizeof(visit));
        dfs(v);
    }

    int ans = 0;
    for (int u = 1; u <= xsiz; ++u)
        if (match[u]) ++ans;
    cout << ans;
}

全部评论

相关推荐

04-15 23:42
中山大学 Java
搞Java不如组一辈子乐队:接好运
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务