素数伴侣问题—>二部图最大匹配问题
2017-04-26 16:41
344 查看
题目描述
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的N(N为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,
而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。
输入:
有一个正偶数N(N≤100),表示待挑选的自然数的个数。后面给出具体的数字,范围为[2,30000]。
输出:
输出一个整数K,表示你求得的“最佳方案”组成“素数伴侣”的对数。
输入描述:
输入说明
1 输入一个正偶数n
2 输入n个整数
输出描述:
求得的“最佳方案”组成“素数伴侣”的对数。
输入例子:
4
2 5 6 13
输出例子:
2
算法思想
考虑使用图论的方法来给这个题建模。 100个数看成100个点,如果这两个数加起来的和是素数,给这两个数中间连一条边。 之后,我们要选择尽可能多的边,要求这些边不共享端点。——这个东西呢,叫做一般无向图的最大匹配。
但是,一般无向图的最大匹配,这个算法的难度,有点,大……
这个问题,合适的算法叫,带花树开花算法。
具体参见:http://blog.csdn.net/yihuikang/article/details/10460997
和 http://fanhq666.blog.163.com/blog/static/8194342620120304463580/
现场推完这么多,写一个正确的,有点不科学……
我们考虑再分析一下这个题 注意到,每个数的取值范围是[2,30000]
素数,除了2是偶数,其他是奇数——而现在不可能出现2了,所以我们只考虑奇数的素数 2个数的和是奇数,有什么情况呢?
只有奇数+偶数 所以,我们把这些数分成2堆——奇数和偶数,然后在他们中间,和是素数的,连上一条边,然后做匹配。
——肯定有人会说,你这个和前面的建图有什么本质不同的地方吗?
——是没有,但是我们说明了得到的图一定是二分图,这是有意义的。
因为对二分图的最大匹配,有一个简单很多的算法,匈牙利算法。
我们先说明一下,什么是二分图。
二分图就是,你可以把图上的点分成2堆,每堆之内的点不会有边,2堆之间,才可能连边。换句话说,一条边,必定连2个来自不同堆的点。
现在,对每条边,一定连一个奇数,一个偶数,点能按奇数和偶数分成两部分,刚好就是二分图嘛!
有关二分图匹配的匈牙利算法,具体请自行搜索,这里扯一下我个人对这个算法的理解。
外层,暴力考虑左边每个点
对枚举的每个左边的点,要找右边一个点来匹配。
那就是对左边的点,我们看他连出去的边,或者说,能连到的右边的点
有2种情况:
1、右边的点没人匹配——我直接贪心匹配上去
2、右边的点有人匹配——考虑把目前与这个右边的点 x 匹配的左边的点
pre[x],重新匹配一个其他的点,如果成功了,那pre[x]原来匹配的点x就释放开了,我可以直接占领上去。
最后统计匹配成功多少个左边的点就行了。
代码块
#include <iostream> #include <vector> #include <string> #include <math.h> using namespace std; vector<int> G[100]; bool visited[100]; int pre[100]; bool isPrime(int k) { if (k <= 2) { return true; } for (int i = 2; i <= sqrt(k); i++) { if (k%i == 0) { return false; } } return true; } bool dfs(int k) { int x; for (int i = 0; i < G[k].size(); ++i) { x = G[k][i]; if (visited[x]) continue; else visited[x] = true; if (pre[x] == 0 || dfs(pre[x])) { pre[x] = k; return true; } } return false; } int main() { int num; while (cin >> num) { int *nums = new int[num + 1]; for (int i = 1; i <= num; ++i) { cin >> nums[i]; } for (int i = 1; i <= num; ++i) { for (int j = i + 1; j <= num; ++j) { if (isPrime(nums[i] + nums[j])) { (nums[i] & 1) ? G[i].push_back(j) : G[j].push_back(i); } } } int count = 0; memset(pre, 0, sizeof(pre)); for (int i = 1; i <= num; ++i) { memset(visited, false, sizeof(visited)); if (dfs(i)) count++; } cout << count << endl; for (int i = 1; i <= num; i++) { G[i].clear(); } } }
相关文章推荐
- 牛客网 素数伴侣(二分图最大匹配,匈牙利算法)
- 白菜Oj 1122: [视频]最大匹配1(二分图)(元问题byscy):公牛母牛配 <匈利亚算法>
- 【网络流24题】 No.3 最小路径覆盖问题 (网络流|匈牙利算法 ->最大二分匹配)
- 素数伴侣--最大二分匹配
- 【网络流二十四题 试题库问题】【二分图多重匹配->最大流】
- POJ 2446 Chessboard 二分图的最大匹配 <建图>
- 二分图最大匹配问题之匈牙利算法
- 老魏帮忙发的木棒问题的最大长度优先匹配原则算法
- Java 正则表达式最大,最小匹配问题
- 正则-贪婪匹配(最大匹配) 和最小匹配的问题。
- 网络流24题(04)圆桌问题(二分图多重匹配 + 最大流)
- 二分图最大匹配问题匈牙利算法
- 字符串的最大匹配问题
- hdu 二分图最大匹配问题 (hdu 1083)
- 二分图的最大匹配问题(匈牙利算法)
- 二分图的最大匹配问题(匈牙利算法)
- 图的应用--二部图的判定及利用匈牙利算法求二部图的最大匹配
- [Matrix67]二分图最大匹配问题匈牙利算法
- 二分图最大匹配问题匈牙利算法
- poj 2195 带权重的二分图最大匹配问题