定义两个正整数 a 和 b 是“素数伴侣”,当且仅当 a+b 是一个素数。 现在,密码学会邀请你设计一个程序,从给定的 n 个正整数 {a1,a2,…,an} 中,挑选出最多的“素数伴侣”,你只需要输出挑选出的“素数伴侣”对数。保证 n 为偶数,一个数字只能使用一次。
输入描述:
第一行输入一个正偶数 n(2≦n≦100) 代表数字个数。
第二行输入 n 个正整数 a1,a2,…,an(1≦ai≦3×104) 代表给定的数字。
输出描述:
输出一个整数,代表最多可以挑选出的“素数伴侣”的数量。
示例
输入:4
2 5 6 13
输出:2
说明: 在这个样例中,2 和 5 可以组成一对素数伴侣,6 和 13 也可以组成一对素数伴侣。因此,最多可以挑选出 2 对素数伴侣。
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
while ((line = await readline())) {
let n = Number(line);
let odd = [];
let even = [];
// 把数据分成奇数和偶数,因为奇数+偶数才能得出奇数,所有素数除了2以外都是奇数
(await readline()).split(" ").forEach((v) => {
v = Number(v);
if (v % 2 === 0) {
even.push(v);
} else {
odd.push(v);
}
});
if (odd.length == 0 || even.length == 0) {
console.log(0);
return;
}
// 遍历并找到所有素数伴侣
const map = [];
for (let i = 0; i < odd.length; i++) {
map[i] = new Array(even.length);
for (let j = 0; j < even.length; j++) {
map[i][j] = isPrime(odd[i] + even[j]);
}
}
let count = 0;
let usedEven = []; // 存放每次遍历里面的偶数下标,防止无限递归
let matchArr = []; // matchArr[j]存放偶数j对应的奇数下标i
for (let i = 0; i < odd.length; i++) {
if (isMach(i)) {
count++;
usedEven = [];
}
}
console.log(count);
function isMach(i) {
for (let j = 0; j < even.length; j++) {
// i、j对应的奇偶数的话如果不是素数或者当前偶数下标在这次isMach递归中已经使用过则直接跳过当前循环
if (!map[i][j] || usedEven[j]) continue;
usedEven[j] = true;
// 如果j没有匹配过,或者原来跟j匹配的奇数matchArr[j]能找到其他匹配
if (matchArr[j] === undefined || isMach(matchArr[j])) {
matchArr[j] = i;
return true;
}
}
return false;
}
function isPrime(n) {
let res = true;
for (let i = 2; i * i <= n; i++) {
if (n % i === 0) {
res = false;
}
}
return res;
}
}
})();