“素数伴侣”:两个自然数的和为素数,则称这两个自然数为“素数伴侣”。现在给定一个数组,内含N<=100个自然数,自然数的范围是[2-30000],求出从该数组中组合出的“素数伴侣”的最大个数(同一个数的使用不能超过重复出现的次数)。如数组 array[]={5,6,6,13,17},输出结果是2。
“素数伴侣”的特点是,成对的两个元素一定在不同的集合当中,即“素数伴侣”的一个元素在奇数集合当中,另一个元素在偶数集合当中。像“素数伴侣”这种,问题的解来自于两个不相交的集合 且求能够匹配的最大个数的问题,是典型的最大二分匹配问题。最大二分匹配一个典型的实际应用是,把一个机器集合L和要同时执行的任务集合R相匹配。
而最大二分匹配问题是多源多汇问题的一个特例,所以它可以完全使用“多源多汇”问题的流网络的解决方法来解决,其中最关键的环节在于寻找“增广路径”。“多源多汇”问题,一共3个集合,源点集合S,汇点集合D,其它点集合P。最大二分匹配问题没有集合P,只有集合S和集合D。同样,最大二分匹配最关键的环节还是寻找“增广路径”。
所以,对最大二分匹配问题的理解和掌握,在于寻找“增广路径”,增广路径也是一条从集合S到集合D的路径,但是它可以反向,从而反向调节之前已经找好的路径。我用一张图简单表示一下什么是“增广路径”,如下:
增广路径的特点是,总会使匹配个数增加,如果找不到增广路径,说明匹配个数达到最大。
下面是“素数伴侣”的代码,其中的最大二分匹配的方法的代码是通用的。
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
using namespace std;
// 判断是否为素数,并将素数存到集合 primes 当中
bool isPrime(int num, set<int>& primes)
{
if (num % 2 == 0) return false;
int sq = static_cast<int>(sqrt(num));
for (int i = 3; i < sq; i += 2)
if (num % i == 0) return false;
primes.insert(num);
return true;
}
// 最大二分匹配
int dfs(vector<vector<int> >& edge, vector<int>& book, vector<int>& match, int u)
{
for (int i = 0; i < book.size(); i++)
if (book[i] == 0 && edge[u][i] == 1) {// edge[u][i] == 1 表示存在 u 到 i 的路径(即素数伴侣),book[i] == 0 表示 i 结点 未被访问
book[i] = 1;// 访问 i 结点,标记为 1
if (match[i] == -1 || dfs(edge, book, match, match[i])) {// 使用递归的方式寻找增广路径
match[i] = u;
match[u] = i;
return 1;// 找到增广路径,调节之前的路径,并返回 1
}
}
return 0;// 没有找到增广路径,返回 0
}
// 求最大个数的素数对,返回素数对的最大个数
int getPrimePairs(vector<int>& nums)
{
sort(nums.begin(), nums.end());
int len = nums.size();
set<int> primes;// 素数集合
vector<vector<int> > edge(len, vector<int>(len, 0));// 所有集合S到集合D的所有原始路径,即所有可能的“素数伴侣”
for (int i = 0; i < len; i++)
for (int j = i + 1; j < len; j++)
if (primes.find(nums[i] + nums[j]) != primes.end() || isPrime(nums[i] + nums[j], primes)) {
edge[i][j] = 1;// == 1 表示 nums[i] 和 nums[j] 构成“素数伴侣”
edge[j][i] = 1;
}
int res = 0;
vector<int> book(len, 0);// 访问的标记数组
vector<int> match(len, -1);// 记录匹配的数据,match[i] == -1 表示 i 结点还没有被匹配
for (int i = 0; i < len; i++) {
if (nums[i] % 2 == 1) continue;// 选择偶数集合的元素
res += dfs(edge, book, match, i);// 找到增广路径 +1,没有找到增广路径 +0
for (int k = 0; k < len; k++) book[k] = 0;
}
return res;
}
int main()
{
int n, num;
cin >> n;
vector<int> nums;
for (int i = 0; i < n; i++) {
cin >> num;
nums.push_back(num);
}
cout << getPrimePairs(nums) << endl;
return 0;
}
本文介绍了一种寻找数组中素数伴侣的最大数量的方法,利用最大二分匹配算法解决这一问题。通过构建合适的图模型,实现了有效的匹配并给出了完整的实现代码。
1018

被折叠的 条评论
为什么被折叠?



