二分图的最大匹配-解决匹配问题
题目描述
题目描述
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如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个整数
输出描述:
求得的“最佳方案”组成“素数伴侣”的对数。
示例1
输入
复制
4
2 5 6 13
输出
复制
2
【问题分析】:
从给定的数中取两个数,这两个数的和满足素数,完成一个匹配,容易知道,其中一个数为偶数,另一个数为奇数
(否则和为偶数,必不可能为素数)
因此将原先的数分成两部分,其中一部分为奇数,另一部分为偶数。
原问题变为:完成从《奇数,偶数》的勾连(勾连的条件为和为素数),使得最终匹配的总数最多
该问题即为二分图的最大匹配,二分图中包含两部分点,每一个点只能与另一部分点中的部分相连
连接两部分中若干点,即两两配对,求最大匹配数。
匈牙利算法:
将点分成上下两部分,奇数arr1[] 和 偶数arr2[]
每一轮考察上面的一个点U 遍历下方的点,对于其中一个点V 若(u,v)能够匹配(如组合成素数) 并且 本轮没有访问到该点
- 那么判断 v点是否已经匹配过,如果没有那么直接匹配
- 如果v点之前匹配过(match[v]!=-1) 那么v点试图抛弃match[v] (即match[v]点能够找到其他匹配的点) 若成功,那么直接抛弃
实现逻辑:
bool find(int u) //奇数第u个寻找偶数匹配 组配成素数组合
{for (int v = 0; v < N; v++){//u v可以组配成素数组合 并且本轮寻找增广路 v还没被讨论(每一轮都要初始化)if (map[u][v] && !visit[v]){visit[v] = true;//若v点还没有匹配(=-1) 或者能够将匹配任务推卸给 v之前的匹配对象if (match[v] == -1 || find(match[v])){match[v] = u; //构建新的匹配return true;}}}return false;}
关键易错点:
visit数组的理解,其在每一轮都需要初始化为false, 一轮可以理解为一个奇数进行匹配,
另外一个实现是素数的判断:
任何一个整数可以划分为6i 6i+1 6i+2 6i+3 6i+4 6i+5
首先6i 6i+2 6i+3 6i+4的类别的数一定不是素数,因为可以被2 或者 3整除
因此只有满足一个数num 其 num%6==1 或 num%6==5才可能为素数
接下来从i=2 循环到 i=sqrt(num) 判断是不是i都不能被num整除
进一步优化:
其中一些i不需要判断,这些i满足 6k 6k+2 6k+3 6k+4
反证法,如果这些i能被num整除,那么num一定也满足 6k 6k+2 6k+3 6k+4 而这与num一定为6k+1或6k+5不符合
bool isPrime(int num)
{int data = num;int loopNum = sqrt(num);for (int i = 2; i <= loopNum; i++){if (data % i == 0){return 0;}}return 1;if (num < 4)return num > 1;//任何的数可以划分为 6i 6i+1 6i+2 6i+3 6i+4 6i+5 //可以看到只能是6i+1 6i+5可能是素数if (num % 6 != 1 && num % 6 != 5)return false;//接下来验证 从i=2到i=sqrt(Num)是否能被Num整除//可以排除 被除数为 6i+2 6i+3 6i+4 6i 反证:如果num能被6i整除 那么num是6的倍数 与num=6i+1或6i+5不符合for (int i = 5; i < sqrt(num); i += 6){if (num % (i) == 0 || num % (i + 2) == 0)return false;}return true;}
如何统计最大匹配数,
即针对每一个奇数,调用find() 若返回true 那么count++
而每一轮结束,初始化visit={false}
完整代码:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<math.h>
using namespace std;
int M, N;
bool visit[100] = { false };//标记一轮中待匹配元素是否被访问数组
int arr1[100] = { -1 };//奇数
int arr2[100] = { -1 };//偶数
bool map[100][100] = { false };//map[i][j]表示奇数的第i个与偶数的第j个组合成素数
int match[100];//match[j]表示第j个偶数的匹配的奇数bool isPrime(int num)
{int data = num;int loopNum = sqrt(num);for (int i = 2; i <= loopNum; i++){if (data % i == 0){return 0;}}return 1;if (num < 4)return num > 1;//任何的数可以划分为 6i 6i+1 6i+2 6i+3 6i+4 6i+5 //可以看到只能是6i+1 6i+5可能是素数if (num % 6 != 1 && num % 6 != 5)return false;//接下来验证 从i=2到i=sqrt(Num)是否能被Num整除//可以排除 被除数为 6i+2 6i+3 6i+4 6i 反证:如果num能被6i整除 那么num是6的倍数 与num=6i+1或6i+5不符合for (int i = 5; i < sqrt(num); i += 6){if (num % (i) == 0 || num % (i + 2) == 0)return false;}return true;}bool find(int u) //奇数第u个寻找偶数匹配 组配成素数组合
{for (int v = 0; v < N; v++){//u v可以组配成素数组合 并且本轮寻找增广路 v还没被讨论(每一轮都要初始化)if (map[u][v] && !visit[v]){visit[v] = true;//若v点还没有匹配(=-1) 或者能够将匹配任务推卸给 v之前的匹配对象if (match[v] == -1 || find(match[v])){match[v] = u; //构建新的匹配return true;}}}return false;}int main()
{int num;cin >> num;for (int i = 0; i < num; i++){int tmp;cin >> tmp;if ((tmp & 1) == 1) //奇数{arr1[M++] = tmp;}else //偶数{arr2[N++] = tmp;}}for (int i = 0; i < M; i++)for (int j = 0; j < N; j++){if (isPrime(arr1[i] + arr2[j])) //和为素数map[i][j] = true;//标记为能匹配}for (int i = 0; i < N; i++)match[i] = -1;int count = 0;for (int i = 0; i < M; i++){//注意每一轮研究 奇数的第i个能否完成匹配,//每一轮研究前 都需要将偶数的每个数初始化为 没有讨论visit=false;for (int j = 0; j < N; j++)visit[j] = false;if (find(i))count++;}cout << count << endl;
}
二分图的最大匹配-解决匹配问题相关推荐
- 二分图的最大匹配 匈牙利算法
基本概念 1.二分图: 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别 ...
- 用匈牙利算法求二分图的最大匹配
转载大神的!! 什么是二分图,什么是二分图的最大匹配,这些定义我就不讲了,网上随便都找得到.二分图的最大匹配有两种求法,第一种是最大流(我在此假设读者已有网络流的知识):第二种就是我现在要讲的匈牙利算 ...
- CF 277.5 B.BerSU Ball 二分图的最大匹配 模版题
题意:求二分图的最大匹配数量 模版如下: //二分图匹配(匈牙利算法的DFS实现) //初始化:g[][]两边顶点的划分情况 //建立g[i][j]表示i->j的有向边就可以了,是左边向右边的匹 ...
- DAG的最小路径覆盖和二分图的最大匹配
DAG的最小路径覆盖和二分图的最大匹配 DAG的最小路径覆盖是指找最小数目的互相不相交的有向路径,满足DAG的所有顶点都被覆盖. 首先给出公式:DAG的最小路径覆盖数=DAG图中的节点数-相应二分图中 ...
- POJ 2584 T-Shirt Gumbo (二分图多重最大匹配)
题意 现在要将5种型号的衣服分发给n个参赛者,然后给出每个参赛者所需要的衣服的尺码的大小范围,在该尺码范围内的衣服该选手可以接受,再给出这5种型号衣服各自的数量,问是否存在一种分配方案使得每个选手都能 ...
- 二分图的最大匹配问题
1.定义 二分图: 将一个图的所有顶点划分为两个不相交集U和V,使得图中的每一条边的顶点分别属于点集合U和点集V,即同一点集中的点不构成边,这样的图叫做二分图.维基百科中给出的无向图G的二分图的充 ...
- 【网络流】基础二分图的最大匹配问题
标题已经说了,所以有基础的牛们就别想在这篇博客里看到什么有价值的东西.这里的解法是最基础的. 二分图是一种可以把图中的点分为两个不同的集合,且同一集合中不存在任意两个有边联通的点(就算是单向边也不行) ...
- Jamie's Contact Groups ——(一对多)二分图多重最大匹配
题目链接:http://poj.org/problem?id=2289 Jamie is a very popular girl and has quite a lot of friends, so ...
- 861. 二分图的最大匹配
861. 二分图的最大匹配 给定一个二分图,其中左半部包含 n1 个点(编号 1∼n1),右半部包含 n2 个点(编号 1∼n2),二分图共包含 m 条边. 数据保证任意一条边的两个端点都不可能在同一 ...
最新文章
- javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())...
- 迎来“进化”风口的电竞,能否在未来站上传统体育的肩膀?
- 文字描边_6招迅速做出炫酷PPT字效!|10分钟干货第二期(文字描边)
- 无限极分类php简单,创建无限极分类树型结构的简单方法
- JAVA基础----简答
- 实测!让M1芯片版mac也能写入NTFS格式磁盘,完整教程附上!
- Java程序员技术栈
- 【狂神说Java】Docker最新超详细版教程通俗易懂笔记
- window.open打开txt文件
- 从零开始编写minecraft光影包(1)基础阴影绘制
- 肤色冷暖色测试软件_认识你自己|肤色冷暖测试
- mysql to sqlserver_mysql to sqlserver
- 苹果内购后台(java)验证订单
- 论文分享 | 可控笔触的快速风格化迁移
- ble 读写特征值特征值_BLE添加特征值
- 变位词算法C语言,程序实现英语变位词的搜索算法
- 纪念一位大师中的大师
- c语言printf( aaa ),有大佬知道那里错了吗。aaa=jia();那报错了#incl
- 如何理解行高和高度?
- MyCat是什么?为什么要用MyCat?