今天刷到一道华为的笔试题:
https://www.nowcoder.com/practice/b9eae162e02f4f928eac37d7699b352e?tpId=37&tqId=21251&tPage=2&rp=&ru=/ta/huawei&qru=/ta/huawei/question-ranking
素数伴侣问题,这道题的思路基本上是:1.将数组中元素分为两部分奇数和偶数,设集合为X(奇数)和Y(偶数),一个素数必然由一个奇数和一个偶数组成,所以开始连线,将所有的可能配对连接到一起:假设数组中的数为:2 5 6 8 11 13 14,则画出二分图如下所示:
那么我们将所求解的问题可以转为图论中的求最搭配对问题,采用匈牙利算法则可解决;
匈牙利算法可以参考这篇博客:
https://blog.csdn.net/u013384984/article/details/90718287
然后总结出匈牙利算法求最大匹配的算法思路如下:
bool 寻找从k出发的对应项出的可增广路
{
while (从邻接表中列举k能关联到顶点j)
{
if (j不在增广路上)
{
把j加入增广路;
if (j是未盖点 或者 从j的对应项出发有可增广路)
{
修改j的对应项为k;
则从k的对应项出有可增广路,返回true;
}
}
}
则从k的对应项出没有可增广路,返回false;
}
void 匈牙利hungary()
{
for i->1 to n
{
if (则从i的对应项出有可增广路)
匹配数++;
}
输出 匹配数;
}**
代码附上:
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdio>
#include <memory>
using namespace std;
vector<int> cx(100, -1);
vector<int> cy(100, -1);
vector<int> visit(100, 0);
int t[100][100] = { 0 };
//判断是否是素数
bool isprime(int n)
{
int m = sqrt(n);
int flag = 0;
for (int i = 2; i <= m; i++)
{
if (n % i == 0)
{
flag = 1;
break;
}
}
if (0 == flag) return true;
return false;
}
//寻找增广路径
int dfs(int u)
{
for (int i = 0; i < 100; i++)
{
if (t[u][i] && !visit[i])
{
visit[i] = 1;
if (cy[i] == -1 || dfs(cy[i]))
{
cx[u] = i;
cy[i] = u;
return 1;
}
}
}
return 0;
}
int main()
{
int N;
vector<int> cj;
vector<int> co;
while (cin >> N)
{
int tmp;
int ans = 0;
for (int i = 0; i < N; i++)
{
cin >> tmp;
if (tmp % 2 != 0) cj.push_back(tmp); //奇数
else co.push_back(tmp); //偶数
}
//画二分图
for (int i = 0; i < cj.size(); i++)
for (int j = 0; j <co.size(); j++)
{
if (isprime(cj[i] + co[j])) t[i][j] = 1; //建立奇数和偶数两个堆中和为素数的连接
}
//匈牙利算法
for (int i = 0; i < cj.size(); i++)
{
if (cx[i] == -1)
{
for (int j = 0; j < visit.size(); j++) visit[j] = 0;
ans += dfs(i);//每次找到增广路径都会多一对
}
}
cout << ans << endl;
//注意要清零
for (int i = 0; i < 100; i++)
for (int j = 0; j < 100; j++)
t[i][j] = 0;
for (int i = 0; i < 100; i++)
cx[i] = cy[i] = -1;
cj.clear();
co.clear();
}
return 0;
}