一、题目

设平面上分布着n个白点和n个黑点,每个点用一对坐标(x, y)表示。一个黑点b=(xb,yb)支配一个白点w=(xw, yw)当且仅当xb>=xw和yb>=yw。

若黑点b支配白点w,则黑点b和白点w可匹配(可形成一个匹配对)。

在一个黑点最多只能与一个白点匹配,一个白点最多只能与一个黑点匹配的前提下,求n个白点和n个黑点的最大匹配对数。

二、解题思路

一看完题目,一开始的思路是先将黑白点分别存入两个数组中,再对两个数组分别进行对x和对y的排序,在实际实验过程中,发现排序完后数组的下标与点不好对应,这样就不容易确定一个点是否已经匹配过。

经过了解查阅后发现了最大匹配问题的算法,和本题类似,而且递归的操作复杂度远小于多次对数组的排序。

而且过多的排序也造成了算法思路难以理清。决定先学习掌握最大匹配度算法再考虑本题…

在查阅了最大匹配度问题的思想后,发现这是一种递归形式的方法,算法需要基于对二分图的遍历算法,这就需要学习DFS或者BFS,所以又去复习了一下这两个算法,在彻底掌握了之后终于可以步入正题了…

(dfs和bfs的执行动态图)

理解了最大匹配算法后,发现只要在图遍历的基础上,多借助一个matching数组,用来储存各匹配点之间的联系,通过一些剪枝和判断就可以实现。

我选择了DFS进行最大匹配算法的基础算法,DFS是对图做出处理,在空间上需要借助一张邻接矩阵,我的想法是将黑白点问题化作图,再根据题目的要求做出对应的邻接矩阵,这样再通过最大匹配就可以求解出来。

下面主要针对这两个问题讨论并通过具体例子演示最大匹配核心思想。

1、如何将黑白点化作图:

创建一个结构体

黑白点都看作顶点,只通过color进行区别

2、如何求对应邻接矩阵:

对储存所有顶点的结构体数组做两次循环,若满足题目中黑点xy坐标大于白点,即将邻接矩阵该位置置为1。

3、具体流程演示:

上图分析:

通过邻接表可以知道,2能控制4,7,8三点

一开始2就控制了4,跳过2点

接着5控制了7,跳过5点

6控制了7,但是7已经被5控制,这时回到5,

5控制了8,跳过5

这时7没人控制,6控制7,流程结束,匹配度为3。

三、代码(DFS BFS两种实现方法)

1 public class MaxMatching {//基于DFS

2

3 static int graph[][]; //邻接表 默认全为0

4 static int n; //节点数

5 static int visit[]; //是否访问

6 static int matched[]; //是否已经匹配,对应的匹配点

7 static vertex V[];结构体数组储存所有黑白

8

9 public class vertex {//顶点结构体

10 public int color;//白:0 黑:1

11 public doubleVx;12 public doubleVy;13 }14

15 public voidInit() {16 System.out.println("输入的黑白点总数为:");17 Scanner sc = newScanner(System.in);18 n =sc.nextInt();19 graph = new int[n][n]; //邻接表 默认全为0

20 visit = new int[n]; //是否访问

21 matched = new int[n]; //是否已经匹配,对应的匹配点

22 V = newvertex[n];23 InitGraph();//初始邻接矩阵

24 }25

26 private voidInitGraph() {27 Scanner sc = newScanner(System.in);28 for (int i = 0; i < n; i++) {//输入黑白点

29 V[i] = newvertex();30 System.out.println("please int color/x/y");31 V[i].color =sc.nextInt();32 V[i].Vx =sc.nextDouble();33 V[i].Vy =sc.nextDouble();34 }35 for (int i = 0; i < n; i++) {36 for (int j = 0; j < n; j++) {37 if (i != j && (V[i].color == 1) && (V[j].color == 0) && (V[i].Vx > V[j].Vx) && (V[i].Vy >V[j].Vy)) {38 graph[i][j] = 1;39 }40 }41 }42 }43

44 //显示匹配结果

45 public voidshow() {46 Arrays.fill(visit, 0);47 for (int i = 0; i < n; i++) {48 if (visit[i] == 0) {49 if (matched[i] != -1) {50 System.out.println("(" + V[i].Vx + "," + V[i].Vy + ")与" + "(" + V[matched[i]].Vx + ","

51 + V[matched[i]].Vy + ")" + "匹配");52 visit[i] = 1;53 visit[matched[i]] = 1;54 }55 }56 }57 }58

59 /*

60 * dfs实现, params: x:起始的未匹配点 return: 1:找到增广路 0:未找到61 */

62 public int dfs_solve(intx) {63 //找到一个和节点存在边的点,并且该点在本轮中没有被访问过

64 for (int i = 0; i < n; i++) {65 if (graph[x][i] != 0 && visit[i] == 0) {66 visit[i] = 1; //标记为匹配过67 //按照交替路的模式找增广路,增广路相对于交替路的特性是就是,第一个节点和最后一个节点都是未匹配过的节点

68 if (matched[i] == -1 || dfs_solve(matched[i]) == 1) { //直接跳到matched[i]能够保证匹配边和未匹配边交替69 //说明找到了一个未匹配节点,将所有匹配边变为未匹配边,将所有未匹配边变为匹配边,这样匹配边数会加1,这个交换过程通过回溯实现

70

71 matched[x] =i;72 matched[i] =x;73

74 System.out75 .println("(" + V[x].Vx + "," + V[x].Vy + ") 与 " + "(" + V[i].Vx + "," + V[i].Vy + ")" + "匹配");76 return 1;77 }78 }79 }80 return 0;81 }82

83 public voidhungarian1() {84 Arrays.fill(matched, -1);85 int sum = 0;86 for (int i = 0; i < n; i++) {87 if (matched[i] == -1) {88 System.out.println("从 " + "(" + V[i].Vx + "," + V[i].Vy + ")" + " 开始匹配");89 Arrays.fill(visit, 0);//重置浏览数组,用来浏览邻接矩阵当前列

90 sum +=dfs_solve(i);91 }92 }93 System.out.println("\n"+"最后共有 " + sum + " 匹配项");94 show();95 }96

97 public static voidmain(String[] args) {98 MaxMatching mm = newMaxMatching();99 mm.Init();100 mm.hungarian1();101 }102 }

文章来源: www.cnblogs.com,作者:脑热,版权归原作者所有,如需转载,请联系作者。

原文链接:https://www.cnblogs.com/Unicron/p/11574652.html

贪心算法黑白点匹配C语言,贪心算法之——黑白点的匹配(两种实现方法)相关推荐

  1. java 贪心算法思路,贪心算法之——黑白点的匹配(两种实现方法),贪心算法...

    贪心算法之--黑白点的匹配(两种实现方法),贪心算法 一.题目 设平面上分布着n个白点和n个黑点,每个点用一对坐标(x, y)表示.一个黑点b=(xb,yb)支配一个白点w=(xw, yw)当且仅当x ...

  2. 快速排序的两种实现方法(c语言版本)

    经过调研发现,对任意无序整数数组,快速排序有两种实现方法,这里简单阐述下思路: 思路一:随意选择一个基准元,一般选择数组的起始元或末尾元,Weiss这本书上特意搞了个算法来选择基准元,--,总之就是基 ...

  3. c语言中用于获取字符串长度的函数是,C语言中求字符串长度的函数的几种实现方法...

    C语言中求字符串长度的函数的几种实现方法 1.最常用的方法是创建一个计数器,判断是否遇到'\0',不是'\0'指针就往后加一. int my_strlen(const char *str) { ass ...

  4. c语言蓝屏代码大全,window_Win10系统出现蓝屏提示错误代码0x00000050两种解决方法,  刚刚升级Win10系统的一段 - phpStudy...

    Win10系统出现蓝屏提示错误代码0x00000050两种解决方法 刚刚升级Win10系统的一段时间,容易出现蓝屏的问题.导致蓝屏故障的原因各不相同,我们需要根据错误代码来执行正确的解决方法.比如,最 ...

  5. R语言生存分析COX回归分析实战:两种治疗方法发生肾功能损害的情况

    R语言生存分析COX回归分析实战:两种治疗方法发生肾功能损害的情况 目录

  6. 三菱V3菱悦智能遥控匹配详细的(两种)方法 配钥匙

    三菱V3菱悦智能遥控匹配详细的(两种)方法 蜂鸣器, V3菱悦, 主机, 遥控器, 报警喇叭 方法遥控器学习 当遥控器损或丢失时可通过重新学习操作将原遥控器信息从主机记忆中删除然后重新学习遥控器 1先 ...

  7. 回文字符串的两种判别方法(c语言)

    C语言判别回文字符的两种简单方法 文章目录 C语言判别回文字符的两种简单方法 一.回文字符串的概念 二.介绍两种判别回文字符串的方法 1.将需要判别的字符串倒序排列再与原字符串对比 2. 通过指针锁定 ...

  8. c语言中将十六进制数转换为十进制数程序,C语言中十六进制转十进制两种实现方法...

    C语言中十六进制转十进制两种实现方法 C语言 · 十六进制转十进制 问题描述 从键盘输入一个不超过8位的正的十六进制数字符串,将它转换为正的十进制数后输出. 注:十六进制数中的10~15分别用大写的英 ...

  9. c语言for循环打印九九乘法口诀的三种简单方法

    c语言for循环打印九九乘法口诀的三种简单方法 由于在学习c语言,今天在复习巩固知识,练习代码的时候,简单的总结了三种for循环打印九九乘法口诀的方法,加深了自己的理解.代码注释和简单的思路已经注释在 ...

最新文章

  1. 统计学习方法笔记 -- 概论
  2. 17.Node.js 回调函数--异步编程
  3. 模型学习 - RNN及一系列发展
  4. vue项目,webpack中配置src路径别名及使用
  5. 交换机该选择千兆还是百兆的呢?
  6. 女士细线毛衣起多少针_从起针到缝合,教你织毛衣的各种要点(详细教程)
  7. python库之numpy
  8. mac虚拟机vm屏幕一直闪烁_VM虚拟机VMware Fusion Pro 11
  9. ++i 和 i++ 性能上的区别
  10. 关于umask函数和creat函数
  11. Word文档打不开怎么办
  12. 关注手机病毒:重点手机安全事件盘点
  13. echarts绘制分时图(2)-- 配置echarts
  14. Unity3D自由摄像头视角旋转,平移,缩放
  15. 数学-向量公式总结和一些公式证明
  16. 区块链三加一:资产不可复制性
  17. 其实大多数人没必要关注iPhone5
  18. ICCV2019——SCRDet Towards More Robust Detection for Small, Cluttered and Rotated Objects
  19. 二叉树的遍历(前序遍历,中序遍历,后序遍历)
  20. Intel迅盘应用从入门到精通

热门文章

  1. 破解压缩文件密码rarcrack
  2. python 爬虫前奏六 ExpectedConditions用法大全
  3. 前端进阶试题css(来自js高级前端开发---豪情)既然被发现了HOHO,那我就置顶了嘿嘿!觉得自己技术OK的可以把这套题目做完哦,然后加入高级前端的社区咯...
  4. cdn之高速缓存服务器的搭建和配置
  5. 筋长一寸寿延十年——leo鉴书67
  6. chrome edge浏览器支持chatGPT3.5/chatGPT4.0
  7. Duplicate class xxxx found in modules
  8. SAR信号处理基础——脉冲压缩/匹配滤波
  9. git——git push 出错
  10. python之wxpython模块学习