题目描述
若两个正整数的和为素数,则这两个正整数称为'素数伴侣',例如 2 和 5、6 和 13。题目要做的事很直接:从给定的 N 个正整数里,尽可能多地配成这样的组合,输出最多能组成多少对。
输入:
有一个正偶数 N(N≤100),表示待挑选的自然数个数。后面跟着 N 个数字,范围是 [2,30000]。
输出:
输出一个整数 K,表示'最佳方案'里素数伴侣的对数。
解题思路
这题看起来像排列组合,实际上是标准的二分图最大匹配。关键点不在'怎么配',而在先把图拆对。
除了 2 以外,素数都是奇数。题目里的数都不小于 2,所以两个数之和如果是素数,基本就得是奇数;而奇数只能由一奇一偶相加得到。也就是说,奇数和偶数天然分属两边,能连边的只会是奇偶配对。
于是问题就变成了:把奇数放左边,偶数放右边,若两数之和是素数,就在它们之间连一条边。接下来要找的是最大匹配,也就是最多能选出多少条互不冲突的边。
实现上用 DFS 找增广路就够了。数据规模不大,匈牙利算法的写法完全能过,而且代码比别的图论套路更顺手。
代码实现
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
vector<int> G[105];
int pre[105];
bool used[105];
bool dfs(int k) {
for (int i = 0; i < G[k].size(); ++i) {
int neighbor = G[k][i];
if (!used[neighbor]) {
used[neighbor] = 1;
if (pre[neighbor] == 0 || dfs(pre[neighbor])) {
pre[neighbor] = k;
return true;
}
}
}
return ;
}
{
isprime[];
(isprime, , (isprime));
( i = ; i <= ; i++) {
j;
(j = ; j < i; j++) {
(i % j == || j * j > i) {
;
}
}
(j * j > i) {
isprime[i] = ;
}
}
N;
nums[];
temp;
(cin >> N) {
( i = ; i <= N; ++i) {
cin >> temp;
nums[i] = temp;
}
( i = ; i <= N; ++i) {
( j = i + ; j <= N; ++j) {
(isprime[nums[i] + nums[j]]) {
(nums[i] % == ) {
G[i].(j);
} {
G[j].(i);
}
}
}
}
(pre, , (pre));
count = ;
( i = ; i <= N; ++i) {
(used, , (used));
((i)) count++;
}
cout << count << endl;
( i = ; i <= N; ++i) G[i].();
}
;
}
