JAVA数独解题(四):数对法
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数独解题(四):数对法相关推荐
- JAVA数独解题(九):数链法(数串、垂直)
JAVA数独解题(九):数链法(数串.垂直) 说明 图片 算法代码 CalcEnum SuLianVerticalCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数独高 ...
- JAVA数独解题(五):X-wing(矩阵法)
JAVA数独解题(五):X-wing(矩阵法) 说明 图片 算法代码 CalcEnum XwingCalc YwingCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数 ...
- JAVA数独解题(七):XYZ-wing
JAVA数独解题(七):XYZ-wing 说明 图片 算法代码 CalcEnum XYZwingCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数独高级技巧:XYZ-w ...
- JAVA数独解题(一):框架搭建
JAVA数独解题(一):框架搭建 前言 环境 创建工程 实体类 Box Sudo 监听器 SudoListener SudoPrintImpl 核心类 SudoHandler 算法组 Abstract ...
- java小编程----四数之和
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满 ...
- leetcode 454. 4Sum II | 454. 四数相加 II(Java)
题目 https://leetcode.com/problems/4sum-ii/ 题解 四数相加问题. 对于左边两个数两两组合,需要维护一个 map,用来存左边两个数的 sum 以及该 sum 对应 ...
- 算法LeetCode解题(C++)-15. 四数之和(难度:中等)
题目描述: 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等 ...
- 算法刷题-哈希表-四数相加
需要哈希的地方都能找到map的身影 第454题.四数相加II 力扣题目链接 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + ...
- ❤️导图整理数组5: 四数之和 相比 三数之和 的大量优化, 力扣18详细注解❤️
此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), ...
最新文章
- Optional 详解 Java
- P1556 幸福的路
- 前端学习(2696):重读vue电商网站17之监听图片上传成功事件
- Oracle 数据库
- 用JavaScript简单编程——基础篇
- HDOJ--2092--整数解(水题)
- js 正则 exec() 和 match() 数据抽取
- HTML中的特殊字符
- 单片机蜂鸣器奏乐代码例子
- Mysql实战练习之简单图书管理系统
- 最新如何将b站视频下载到电脑上不用插件
- 四年前,我设计了一款纹胸小样儿……如图……
- meaven install提示系统资源不足
- 智慧电厂三维可视化定位技术,高效管控人员/车辆
- 2356,2372,2377,2388,2394
- CL210管理存储--管理共享文件系统
- 用魔法打败魔法!这件毛衣让摄像头看不到你;两款酷炫的AI写作软件;基于深度学习扩散模型的蛋白质设计;Codon开源Python编译器;基于AI生成连贯的剧本 | ShowMeAI资讯日报
- 无刷直流电机MATLAB仿真,基于有感无感两种方式 无刷直流电机霍尔换相建模
- ibooks 安卓 php,ibooks安卓版
- 语音验证码短信原理和应用场景分析