JAVA数独解题(四):数对法

  • 说明
  • 图片
  • 算法代码
    • CalcEnum
    • SuDuiCalc
    • SudoUtil
    • 输出结果
  • 总结
  • 代码详情

说明

数对:两个单元格,两个数字。两个数字在当前区域(行、列、宫)中,只能在这两个单元格内出现,则形成数对。
作用:如果形成数对,则能够确定这两个单元格只能填写这两个数字,其他数字不能出现,都可以剔除,并且同区域内,其他单元格不能填写这两个数字。

图片


如上图所示,第1宫内,有两个空白格只能填入8和9,则这两个单元格与89形成数对,其余单元格内不能填入89。则可以排除。
并且在所处的列中,也能排除。

再看一个隐藏比较深入的,如下图

上图在第3宫中,4和6只能填写在这两个单元格,故形成46数对,排除本身单元格内的其他数字。所以8只能出现在第3行第9列的位置。

算法代码

CalcEnum

在 绑定算法 中添加 属性

package com.suduku.calc.enums;import com.suduku.calc.*;
import lombok.AllArgsConstructor;
import lombok.Getter;import java.util.HashMap;
import java.util.Map;/*** 功能描述: 算法枚举 <br/>**/
@Getter
@AllArgsConstructor
public enum CalcEnum {/***/ONLY_NUM(OnlyNumCalc.class, "唯余法", "唯一余数法(当前单元格中,候选数字只有一个)"),ONLY_BOX(OnlyBoxCalc.class, "摒除法", "摒除法(数字在所在行或列或宫中,只有一个空格能够填写,则确定是唯一数字)"),GRID_XY(GridXYCalc.class, "单宫行列法", "单宫行列法()"),SU_DUI(SuDuiCalc.class, "数对法", "数对法(一个区域内,两个数字只能在两个单元格内,则形成数对,其他值不能填入)"),;private static final Map<Class<? extends AbstractCalc>, CalcEnum> CE_MAP = new HashMap<>(CalcEnum.values().length);static {for(CalcEnum ce : CalcEnum.values()) {CE_MAP.put(ce.getClazz(), ce);}}/*** 功能描述: 通过类,获取枚举 <br/>** @param clazz 类* @return "com.suduku.calc.enums.CalcEnum"*/public static CalcEnum indexOf(Class<? extends AbstractCalc> clazz) {return CE_MAP.get(clazz);}private Class<? extends AbstractCalc> clazz;private String name;private String msg;}

SuDuiCalc

package com.suduku.calc;import com.suduku.entity.Box;
import com.suduku.util.SudoUtil;import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;/*** 数对法(一个区域内,两个数字只能在两个单元格内,则形成数对,其他值不能填入) <br/>** 测试数据:DataConstant.XING_02_23*/
public class SuDuiCalc extends AbstractCalc {@OverrideBox solve() {// 判断宫内数对Box box = twoNumBox(getGMap());if(box != null) {return box;}// 判断行内数对box = twoNumBox(getXMap());if(box != null) {return box;}// 判断列内数对box = twoNumBox(getYMap());if(box != null) {return box;}return null;}/*** 功能描述: 查找区域内的数对 <br/>** @param areaMap 区域集合* @return "com.suduku.entity.Box"*/private Box twoNumBox(Map<Integer, List<Box>> areaMap) {// 遍历所有区域Set<Map.Entry<Integer, List<Box>>> entries = areaMap.entrySet();for (Map.Entry<Integer, List<Box>> entry : entries) {List<Box> list = entry.getValue();// 查找区域内候选字是两个数字,并且候选数字相同,且只有两个单元格的情况,形成数对List<Box> nmList = SudoUtil.findSuDuiBoxList(list);if(nmList != null && nmList.size() == 2 && SudoUtil.isEqTwoList(nmList.get(0).getCList(), nmList.get(1).getCList())) {// 形成数对,则可以排除区域其他宫内的情况// 获取数对的下标List<Integer> suDuiIndexs = nmList.stream().map(Box::getI).collect(Collectors.toList());List<Box> clearBoxList = list.stream().filter(b -> b.isBlank() && !suDuiIndexs.contains(b.getI()) && (b.getCList().contains(nmList.get(0).getCList().get(0)) || b.getCList().contains(nmList.get(0).getCList().get(1)))).collect(Collectors.toList());for (Box box : clearBoxList) {// 是空白格,不是数对单元格,包含数对数字getListener().sendMsg("确定数对为【%d, %d】,移除数对区域其他单元格数对数字。\n", nmList.get(0).getCList().get(0), nmList.get(0).getCList().get(1));box.getCList().removeAll(nmList.get(0).getCList());return box;}}// 遍历 1 ~ 9 个数字,在候选值中是否只有两个空白格for(Integer n : Box.INIT_LIST) {List<Box> nList = list.stream().filter(b -> b.isBlank() && b.getCList().contains(n)).collect(Collectors.toList());// 如果在该区域内,只有两个单元格if(nList.size() == 2) {// 遍历下一个数字,并且数字大于第一个数字(减少次数)for(Integer m : Box.INIT_LIST) {if(m > n) {List<Box> mList = list.stream().filter(b -> b.isBlank() && b.getCList().contains(m)).collect(Collectors.toList());// 如果也是只有两个单元格,并且与第一个数字的两个单元格相等。则形成数对if(mList.size() == 2 && SudoUtil.isEqBoxList(nList, mList)) {// 形成数对,开始剔除数据List<Integer> suDuiList = SudoUtil.getList(n, m);// 1、剔除本身两个单元格for(Box box : nList) {if(box.getCList().size() > 2) {getListener().sendMsg("确定数对为【%d, %d】,移除数对单元格其余数字。\n", n, m);box.setCList(suDuiList);return box;}}// 2、剔除区域内的其他单元格// 获取数对的下标List<Integer> suDuiIndexs = nList.stream().map(Box::getI).collect(Collectors.toList());// 遍历当前区域for (Box box : list) {// 是空白格,不是数对单元格,包含数对数字if(box.isBlank() && !suDuiIndexs.contains(box.getI()) && (box.getCList().contains(n) || box.getCList().contains(m))) {getListener().sendMsg("确定数对为【%d, %d】,移除数对区域其他单元格数对数字。\n", n, m);box.getCList().removeAll(suDuiList);return box;}}}}}}}}return null;}}

SudoUtil

    /*** 功能描述: 发现数对 <br/>** @param towCLists 待发现的数对* @return "java.util.List<com.suduku.entity.Box>"*/public static List<Box> findSuDuiBoxList(List<Box> towCLists) {for(Box b1 : towCLists) {for(Box b2 : towCLists) {if(b1.isBlank() && b2.isBlank() && b1.getI() != b2.getI()) {if(b1.getCList().size() == 2 && isEqTwoList(b1.getCList(), b2.getCList())) {return getList(b1, b2);}}}}return null;}

输出结果

尝试【  数对法 】
确定数对为【4, 6】移除数对单元格其余数字。
确认位置【行:1,列:8】  值为:【】    候选值为:【4,6】0 (12       ) 0 (12789    ) 0 (89       ) |  0 (179      ) 0 (579      ) 0 (12579    ) |  3 (         ){0}(46       ) 0 (246789   ) | 5 (         ) 0 (12379    ) 4 (         ) |  6 (         ) 8 (         ) 0 (12379    ) |  0 (129      ) 0 (1279     ) 0 (279      ) | 6 (         ) 0 (123789   ) 0 (89       ) |  0 (1379     ) 0 (79       ) 4 (         ) |  5 (         ) 0 (1279     ) 0 (2789     ) | 0 (79       ) 6 (         ) 1 (         ) |  2 (         ) 3 (         ) 8 (         ) |  0 (49       ) 5 (         ) 0 (479      ) | 8 (         ) 5 (         ) 2 (         ) |  0 (79       ) 4 (         ) 0 (79       ) |  6 (         ) 3 (         ) 1 (         ) | 0 (79       ) 4 (         ) 3 (         ) |  5 (         ) 1 (         ) 6 (         ) |  8 (         ) 0 (279      ) 0 (279      ) | 0 (12       ) 0 (1289     ) 0 (5689     ) |  0 (134789   ) 0 (5679     ) 0 (13579    ) |  0 (1249     ) 0 (12469    ) 0 (23469    ) | 3 (         ) 0 (1289     ) 7 (         ) |  0 (1489     ) 0 (69       ) 0 (19       ) |  0 (1249     ) 0 (12469    ) 5 (         ) | 4 (         ) 0 (19       ) 0 (569      ) |  0 (139      ) 2 (         ) 0 (1359     ) |  7 (         ) 8 (         ) 0 (369      ) | 尝试【  数对法 】
确定数对为【4, 6】移除数对单元格其余数字。
确认位置【行:1,列:9】  值为:【】    候选值为:【4,6】0 (12       ) 0 (12789    ) 0 (89       ) |  0 (179      ) 0 (579      ) 0 (12579    ) |  3 (         ) 0 (46       ){0}(46       ) | 5 (         ) 0 (12379    ) 4 (         ) |  6 (         ) 8 (         ) 0 (12379    ) |  0 (129      ) 0 (1279     ) 0 (279      ) | 6 (         ) 0 (123789   ) 0 (89       ) |  0 (1379     ) 0 (79       ) 4 (         ) |  5 (         ) 0 (1279     ) 0 (2789     ) | 0 (79       ) 6 (         ) 1 (         ) |  2 (         ) 3 (         ) 8 (         ) |  0 (49       ) 5 (         ) 0 (479      ) | 8 (         ) 5 (         ) 2 (         ) |  0 (79       ) 4 (         ) 0 (79       ) |  6 (         ) 3 (         ) 1 (         ) | 0 (79       ) 4 (         ) 3 (         ) |  5 (         ) 1 (         ) 6 (         ) |  8 (         ) 0 (279      ) 0 (279      ) | 0 (12       ) 0 (1289     ) 0 (5689     ) |  0 (134789   ) 0 (5679     ) 0 (13579    ) |  0 (1249     ) 0 (12469    ) 0 (23469    ) | 3 (         ) 0 (1289     ) 7 (         ) |  0 (1489     ) 0 (69       ) 0 (19       ) |  0 (1249     ) 0 (12469    ) 5 (         ) | 4 (         ) 0 (19       ) 0 (569      ) |  0 (139      ) 2 (         ) 0 (1359     ) |  7 (         ) 8 (         ) 0 (369      ) |

最终结果

 1 (         ) 7 (         ) 8 (         ) |  9 (         ) 5 (         ) 2 (         ) |  3 (         ) 4 (         ) 6 (         ) | 5 (         ) 2 (         ) 4 (         ) |  6 (         ) 8 (         ) 3 (         ) |  1 (         ) 9 (         ) 7 (         ) | 6 (         ) 3 (         ) 9 (         ) |  1 (         ) 7 (         ) 4 (         ) |  5 (         ) 2 (         ) 8 (         ) | 7 (         ) 6 (         ) 1 (         ) |  2 (         ) 3 (         ) 8 (         ) |  9 (         ) 5 (         ) 4 (         ) | 8 (         ) 5 (         ) 2 (         ) |  7 (         ) 4 (         ) 9 (         ) |  6 (         ) 3 (         ) 1 (         ) | 9 (         ) 4 (         ) 3 (         ) |  5 (         ) 1 (         ) 6 (         ) |  8 (         ) 7 (         ) 2 (         ) | 2 (         ) 9 (         ) 5 (         ) |  8 (         ) 6 (         ) 7 (         ) |  4 (         ) 1 (         ) 3 (         ) | 3 (         ) 8 (         ) 7 (         ) |  4 (         ) 9 (         ) 1 (         ) |  2 (         ){6}(         ) 5 (         ) | 4 (         ) 1 (         ) 6 (         ) |  3 (         ) 2 (         ) 5 (         ) |  7 (         ) 8 (         ) 9 (         ) | ============数独解题完成,尝试次数为:82============

总结

数对属于数独解法中的中级用法,熟练掌握可以快速解决大部分数独。在Sudo Cool 这个app的 2星难度,只需要掌握数对,就能全部通关。

代码详情

代码地址

JAVA数独解题(四):数对法相关推荐

  1. JAVA数独解题(九):数链法(数串、垂直)

    JAVA数独解题(九):数链法(数串.垂直) 说明 图片 算法代码 CalcEnum SuLianVerticalCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数独高 ...

  2. JAVA数独解题(五):X-wing(矩阵法)

    JAVA数独解题(五):X-wing(矩阵法) 说明 图片 算法代码 CalcEnum XwingCalc YwingCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数 ...

  3. JAVA数独解题(七):XYZ-wing

    JAVA数独解题(七):XYZ-wing 说明 图片 算法代码 CalcEnum XYZwingCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数独高级技巧:XYZ-w ...

  4. JAVA数独解题(一):框架搭建

    JAVA数独解题(一):框架搭建 前言 环境 创建工程 实体类 Box Sudo 监听器 SudoListener SudoPrintImpl 核心类 SudoHandler 算法组 Abstract ...

  5. java小编程----四数之和

    给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满 ...

  6. leetcode 454. 4Sum II | 454. 四数相加 II(Java)

    题目 https://leetcode.com/problems/4sum-ii/ 题解 四数相加问题. 对于左边两个数两两组合,需要维护一个 map,用来存左边两个数的 sum 以及该 sum 对应 ...

  7. 算法LeetCode解题(C++)-15. 四数之和(难度:中等)

    题目描述: 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等 ...

  8. 算法刷题-哈希表-四数相加

    需要哈希的地方都能找到map的身影 第454题.四数相加II 力扣题目链接 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + ...

  9. ❤️导图整理数组5: 四数之和 相比 三数之和 的大量优化, 力扣18详细注解❤️

    此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), ...

最新文章

  1. Optional 详解 Java
  2. P1556 幸福的路
  3. 前端学习(2696):重读vue电商网站17之监听图片上传成功事件
  4. Oracle 数据库
  5. 用JavaScript简单编程——基础篇
  6. HDOJ--2092--整数解(水题)
  7. js 正则 exec() 和 match() 数据抽取
  8. HTML中的特殊字符
  9. 单片机蜂鸣器奏乐代码例子
  10. Mysql实战练习之简单图书管理系统
  11. 最新如何将b站视频下载到电脑上不用插件
  12. 四年前,我设计了一款纹胸小样儿……如图……
  13. meaven install提示系统资源不足
  14. 智慧电厂三维可视化定位技术,高效管控人员/车辆
  15. 2356,2372,2377,2388,2394
  16. CL210管理存储--管理共享文件系统
  17. 用魔法打败魔法!这件毛衣让摄像头看不到你;两款酷炫的AI写作软件;基于深度学习扩散模型的蛋白质设计;Codon开源Python编译器;基于AI生成连贯的剧本 | ShowMeAI资讯日报
  18. 无刷直流电机MATLAB仿真,基于有感无感两种方式 无刷直流电机霍尔换相建模
  19. ibooks 安卓 php,ibooks安卓版
  20. 语音验证码短信原理和应用场景分析

热门文章

  1. 入门3D游戏建模,有哪些建模软件可以选择?
  2. Replacing Elements (CodeForces - 1473A)
  3. 中小创势如破竹未来投资机会在哪
  4. 内网安全(四)---横向渗透:PTHPTKPTT
  5. 下一代 TGW 从13Mpps到50Mpps性能优化之旅
  6. gif原理+gifsicle压缩gif
  7. 使用Telerik的登陆模板实现DoubanFm的登陆(WP7)
  8. 自动驾驶创业方向有变化?如何突破技术瓶颈?
  9. 如何把操作系统迁移到新硬盘?
  10. unity内部自带局域网制作