JAVA数独解题(五):X-wing(矩阵法)
JAVA数独解题(五):X-wing(矩阵法)
- 说明
- 图片
- 算法代码
- CalcEnum
- XwingCalc
- YwingCalc
- SudoUtil
- 测试数据
- 输出结果
- 总结
- 代码详情
说明
参考文章:数独高级技巧:X-wing的原理和应用(19年12月4日)
假设同一列中,一个数字n只能有两个空白格可以填写,并且不在同一宫中。同时存在这个数字n在另外一列由相同的情况,这时,如果四个空白格形成一个矩形。则可以排除顶点所在行的其他空白格中的候选值n。
同理衍生到行的情况,这里代码写作Y-wing。
图片
算法代码
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, "数对法", "数对法(一个区域内,两个数字只能在两个单元格内,则形成数对,其他值不能填入)"),X_WING(XwingCalc.class, "X-wing", "X-wing(如果在同一列,并且不在同一宫中,存在数字n只有两个单元格可以填写;并且不在这两宫的其他列存在相同的情况,则可以排除在这两行中,其他位置的数字n的情况)"),Y_WING(YwingCalc.class, "Y-wing", "X-wing对应"),;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;}
XwingCalc
package com.suduku.calc;import com.suduku.entity.Box;import java.util.*;
import java.util.stream.Collectors;/*** X-wing(如果在同一列,并且不在同一宫中,存在数字n只有两个单元格可以填写;并且不在这两宫的其他列存在相同的情况,则可以排除在这两行中,其他位置的数字n的情况) <br/>* 与X-wing相对应的,横向也是满足的。* 将行和列合并起来,形成矩形。就能够排除4个顶点所在的行列的其余空白格的数字。* 测试数据:DataConstant.OTHER_X_WING_01*/
public class XwingCalc extends AbstractCalc {@OverrideBox solve() {// 遍历数字for(Integer n : Box.INIT_LIST) {Set<Map.Entry<Integer, List<Box>>> entries = getYMap().entrySet();// 遍历区域for(Map.Entry<Integer, List<Box>> e1 : entries) {// 获取当前区域包含数字n的空白格List<Box> b1List = e1.getValue().stream().filter(b -> b.isBlank() && b.getCList().contains(n)).collect(Collectors.toList());// 如果只有两个空白格,并且不在同一宫中if(b1List.size() == 2 && b1List.get(0).getG() != b1List.get(1).getG()) {// 遍历第二遍for(Map.Entry<Integer, List<Box>> e2 : entries) {if(e2.getKey() > e1.getKey()) {// 获取当前区域包含数字n的空白格List<Box> b2List = e2.getValue().stream().filter(b -> b.isBlank() && b.getCList().contains(n)).collect(Collectors.toList());// 如果只有两个空白格,并且不在同一宫中if(b2List.size() == 2 && b2List.get(0).getG() != b2List.get(1).getG()) {// 判断是否在同一行中if(b1List.get(0).getX() == b2List.get(0).getX() && b1List.get(1).getX() == b2List.get(1).getX()) {Box box = clearBoxNum(b1List.get(0), b2List.get(0), n);if(box != null) {return box;}box = clearBoxNum(b1List.get(1), b2List.get(1), n);if(box != null) {return box;}}}}}}}}return null;}/*** 功能描述: 清理数字 <br/>** @param b1 同一列的单元格1* @param b2 同一列的单元格2* @param n 移除的数字* @return "com.suduku.entity.Box"*/private Box clearBoxNum(Box b1, Box b2, Integer n) {List<Box> clearBoxList = getXList(b1).stream().filter(b -> b.isBlank() && b.getI() != b1.getI() && b.getI() != b2.getI() && b.getCList().contains(n)).collect(Collectors.toList());for (Box box : clearBoxList) {getListener().sendMsg("移除第【%d】行的数字:%d\n", (b1.getX() + 1), n);box.getCList().remove(n);return box;}return null;}}
YwingCalc
package com.suduku.calc;import com.suduku.entity.Box;import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;/*** 与X-wing对应* 测试数据:SudoUtil.transpose(DataConstant.OTHER_X_WING_01) 转置后的数独*/
public class YwingCalc extends AbstractCalc {@OverrideBox solve() {// 遍历数字for(Integer n : Box.INIT_LIST) {Set<Map.Entry<Integer, List<Box>>> entries = getXMap().entrySet();// 遍历区域for(Map.Entry<Integer, List<Box>> e1 : entries) {// 获取当前区域包含数字n的空白格List<Box> b1List = e1.getValue().stream().filter(b -> b.isBlank() && b.getCList().contains(n)).collect(Collectors.toList());// 如果只有两个空白格,并且不在同一宫中if(b1List.size() == 2 && b1List.get(0).getG() != b1List.get(1).getG()) {// 遍历第二遍for(Map.Entry<Integer, List<Box>> e2 : entries) {if(e2.getKey() > e1.getKey()) {// 获取当前区域包含数字n的空白格List<Box> b2List = e2.getValue().stream().filter(b -> b.isBlank() && b.getCList().contains(n)).collect(Collectors.toList());// 如果只有两个空白格,并且不在同一宫中if(b2List.size() == 2 && b2List.get(0).getG() != b2List.get(1).getG()) {// 判断是否在同一行中if(b1List.get(0).getY() == b2List.get(0).getY() && b1List.get(1).getY() == b2List.get(1).getY()) {Box box = clearBoxNum(b1List.get(0), b2List.get(0), n);if(box != null) {return box;}box = clearBoxNum(b1List.get(1), b2List.get(1), n);if(box != null) {return box;}}}}}}}}return null;}/*** 功能描述: 清理数字 <br/>** @param b1 同一行的单元格1* @param b2 同一行的单元格2* @param n 移除的数字* @return "com.suduku.entity.Box"*/private Box clearBoxNum(Box b1, Box b2, Integer n) {List<Box> clearBoxList = getYList(b1).stream().filter(b -> b.isBlank() && b.getI() != b1.getI() && b.getI() != b2.getI() && b.getCList().contains(n)).collect(Collectors.toList());for (Box box : clearBoxList) {getListener().sendMsg("移除第【%d】列的数字:%d\n", (b1.getX() + 1), n);box.getCList().remove(n);return box;}return null;}}
由于没有找到Y-wing的案例,所以通过矩阵转置来产生场景。在SoduUtil中添加转置代码
SudoUtil
/*** 功能描述: 转置 <br/>* * @param str 数独字符串* @return "java.lang.String"*/public static String transpose(String str) {char[] cs = str.toCharArray();char[] rs = new char[cs.length];for (int i = 0; i < cs.length; i++) {// 行列互换rs[(i % 9) * 9 + i / 9] = cs[i];}return new String(rs);}
测试数据
在 DataConstant 中添加
public static final String OTHER_X_WING_01 = "000300100500401090001028600090800001008017002010040800004085000300100040002634000";
输出结果
尝试【X-wing 】
移除第【1】行的数字:9
确认位置【行:1,列:1】 值为:【】 候选值为:【4,6,7,8】
{0}(4678 ) 0 (2467 ) 0 (679 ) | 3 ( ) 0 (5679 ) 0 (69 ) | 1 ( ) 0 (2578 ) 0 (457 ) | 5 ( ) 0 (23678 ) 0 (367 ) | 4 ( ) 0 (67 ) 1 ( ) | 0 (237 ) 9 ( ) 0 (378 ) | 0 (479 ) 0 (347 ) 1 ( ) | 0 (579 ) 2 ( ) 8 ( ) | 6 ( ) 0 (357 ) 0 (3457 ) | 0 (2467 ) 9 ( ) 0 (3567 ) | 8 ( ) 0 (56 ) 0 (236 ) | 0 (3457 ) 0 (3567 ) 1 ( ) | 0 (46 ) 0 (3456 ) 8 ( ) | 0 (59 ) 1 ( ) 7 ( ) | 0 (3459 ) 0 (356 ) 2 ( ) | 0 (267 ) 1 ( ) 0 (3567 ) | 0 (259 ) 4 ( ) 0 (2369 ) | 8 ( ) 0 (3567 ) 0 (35679 ) | 0 (1679 ) 0 (67 ) 4 ( ) | 0 (279 ) 8 ( ) 5 ( ) | 0 (2379 ) 0 (12367 ) 0 (3679 ) | 3 ( ) 0 (5678 ) 0 (5679 ) | 1 ( ) 0 (79 ) 0 (29 ) | 0 (2579 ) 4 ( ) 0 (56789 ) | 0 (1789 ) 0 (57 ) 2 ( ) | 6 ( ) 3 ( ) 4 ( ) | 0 (579 ) 0 (1578 ) 0 (579 ) | 尝试【X-wing 】
移除第【1】行的数字:9
确认位置【行:1,列:6】 值为:【】 候选值为:【6】0 (4678 ) 0 (2467 ) 0 (679 ) | 3 ( ) 0 (5679 ){0}(6 ) | 1 ( ) 0 (2578 ) 0 (457 ) | 5 ( ) 0 (23678 ) 0 (367 ) | 4 ( ) 0 (67 ) 1 ( ) | 0 (237 ) 9 ( ) 0 (378 ) | 0 (479 ) 0 (347 ) 1 ( ) | 0 (579 ) 2 ( ) 8 ( ) | 6 ( ) 0 (357 ) 0 (3457 ) | 0 (2467 ) 9 ( ) 0 (3567 ) | 8 ( ) 0 (56 ) 0 (236 ) | 0 (3457 ) 0 (3567 ) 1 ( ) | 0 (46 ) 0 (3456 ) 8 ( ) | 0 (59 ) 1 ( ) 7 ( ) | 0 (3459 ) 0 (356 ) 2 ( ) | 0 (267 ) 1 ( ) 0 (3567 ) | 0 (259 ) 4 ( ) 0 (2369 ) | 8 ( ) 0 (3567 ) 0 (35679 ) | 0 (1679 ) 0 (67 ) 4 ( ) | 0 (279 ) 8 ( ) 5 ( ) | 0 (2379 ) 0 (12367 ) 0 (3679 ) | 3 ( ) 0 (5678 ) 0 (5679 ) | 1 ( ) 0 (79 ) 0 (29 ) | 0 (2579 ) 4 ( ) 0 (56789 ) | 0 (1789 ) 0 (57 ) 2 ( ) | 6 ( ) 3 ( ) 4 ( ) | 0 (579 ) 0 (1578 ) 0 (579 ) | 尝试【X-wing 】
移除第【8】行的数字:9
确认位置【行:8,列:6】 值为:【】 候选值为:【2】0 (4678 ) 0 (2467 ) 0 (679 ) | 3 ( ) 0 (5679 ) 0 (6 ) | 1 ( ) 0 (2578 ) 0 (457 ) | 5 ( ) 0 (23678 ) 0 (367 ) | 4 ( ) 0 (67 ) 1 ( ) | 0 (237 ) 9 ( ) 0 (378 ) | 0 (479 ) 0 (347 ) 1 ( ) | 0 (579 ) 2 ( ) 8 ( ) | 6 ( ) 0 (357 ) 0 (3457 ) | 0 (2467 ) 9 ( ) 0 (3567 ) | 8 ( ) 0 (56 ) 0 (236 ) | 0 (3457 ) 0 (3567 ) 1 ( ) | 0 (46 ) 0 (3456 ) 8 ( ) | 0 (59 ) 1 ( ) 7 ( ) | 0 (3459 ) 0 (356 ) 2 ( ) | 0 (267 ) 1 ( ) 0 (3567 ) | 0 (259 ) 4 ( ) 0 (2369 ) | 8 ( ) 0 (3567 ) 0 (35679 ) | 0 (1679 ) 0 (67 ) 4 ( ) | 0 (279 ) 8 ( ) 5 ( ) | 0 (2379 ) 0 (12367 ) 0 (3679 ) | 3 ( ) 0 (5678 ) 0 (5679 ) | 1 ( ) 0 (79 ){0}(2 ) | 0 (2579 ) 4 ( ) 0 (56789 ) | 0 (1789 ) 0 (57 ) 2 ( ) | 6 ( ) 3 ( ) 4 ( ) | 0 (579 ) 0 (1578 ) 0 (579 ) | 尝试【X-wing 】
移除第【8】行的数字:9
确认位置【行:8,列:7】 值为:【】 候选值为:【2,5,7】0 (4678 ) 0 (2467 ) 0 (679 ) | 3 ( ) 0 (5679 ) 0 (6 ) | 1 ( ) 0 (2578 ) 0 (457 ) | 5 ( ) 0 (23678 ) 0 (367 ) | 4 ( ) 0 (67 ) 1 ( ) | 0 (237 ) 9 ( ) 0 (378 ) | 0 (479 ) 0 (347 ) 1 ( ) | 0 (579 ) 2 ( ) 8 ( ) | 6 ( ) 0 (357 ) 0 (3457 ) | 0 (2467 ) 9 ( ) 0 (3567 ) | 8 ( ) 0 (56 ) 0 (236 ) | 0 (3457 ) 0 (3567 ) 1 ( ) | 0 (46 ) 0 (3456 ) 8 ( ) | 0 (59 ) 1 ( ) 7 ( ) | 0 (3459 ) 0 (356 ) 2 ( ) | 0 (267 ) 1 ( ) 0 (3567 ) | 0 (259 ) 4 ( ) 0 (2369 ) | 8 ( ) 0 (3567 ) 0 (35679 ) | 0 (1679 ) 0 (67 ) 4 ( ) | 0 (279 ) 8 ( ) 5 ( ) | 0 (2379 ) 0 (12367 ) 0 (3679 ) | 3 ( ) 0 (5678 ) 0 (5679 ) | 1 ( ) 0 (79 ) 0 (2 ) | {0}(257 ) 4 ( ) 0 (56789 ) | 0 (1789 ) 0 (57 ) 2 ( ) | 6 ( ) 3 ( ) 4 ( ) | 0 (579 ) 0 (1578 ) 0 (579 ) | 尝试【X-wing 】
移除第【8】行的数字:9
确认位置【行:8,列:9】 值为:【】 候选值为:【5,6,7,8】0 (4678 ) 0 (2467 ) 0 (679 ) | 3 ( ) 0 (5679 ) 0 (6 ) | 1 ( ) 0 (2578 ) 0 (457 ) | 5 ( ) 0 (23678 ) 0 (367 ) | 4 ( ) 0 (67 ) 1 ( ) | 0 (237 ) 9 ( ) 0 (378 ) | 0 (479 ) 0 (347 ) 1 ( ) | 0 (579 ) 2 ( ) 8 ( ) | 6 ( ) 0 (357 ) 0 (3457 ) | 0 (2467 ) 9 ( ) 0 (3567 ) | 8 ( ) 0 (56 ) 0 (236 ) | 0 (3457 ) 0 (3567 ) 1 ( ) | 0 (46 ) 0 (3456 ) 8 ( ) | 0 (59 ) 1 ( ) 7 ( ) | 0 (3459 ) 0 (356 ) 2 ( ) | 0 (267 ) 1 ( ) 0 (3567 ) | 0 (259 ) 4 ( ) 0 (2369 ) | 8 ( ) 0 (3567 ) 0 (35679 ) | 0 (1679 ) 0 (67 ) 4 ( ) | 0 (279 ) 8 ( ) 5 ( ) | 0 (2379 ) 0 (12367 ) 0 (3679 ) | 3 ( ) 0 (5678 ) 0 (5679 ) | 1 ( ) 0 (79 ) 0 (2 ) | 0 (257 ) 4 ( ){0}(5678 ) | 0 (1789 ) 0 (57 ) 2 ( ) | 6 ( ) 3 ( ) 4 ( ) | 0 (579 ) 0 (1578 ) 0 (579 ) |
最终结果
尝试【唯余法 】
确认位置【行:9,列:9】 值为:【9】 候选值为:【】8 ( ) 7 ( ) 9 ( ) | 3 ( ) 5 ( ) 6 ( ) | 1 ( ) 2 ( ) 4 ( ) | 5 ( ) 2 ( ) 6 ( ) | 4 ( ) 7 ( ) 1 ( ) | 3 ( ) 9 ( ) 8 ( ) | 4 ( ) 3 ( ) 1 ( ) | 9 ( ) 2 ( ) 8 ( ) | 6 ( ) 5 ( ) 7 ( ) | 2 ( ) 9 ( ) 5 ( ) | 8 ( ) 6 ( ) 3 ( ) | 4 ( ) 7 ( ) 1 ( ) | 6 ( ) 4 ( ) 8 ( ) | 5 ( ) 1 ( ) 7 ( ) | 9 ( ) 3 ( ) 2 ( ) | 7 ( ) 1 ( ) 3 ( ) | 2 ( ) 4 ( ) 9 ( ) | 8 ( ) 6 ( ) 5 ( ) | 9 ( ) 6 ( ) 4 ( ) | 7 ( ) 8 ( ) 5 ( ) | 2 ( ) 1 ( ) 3 ( ) | 3 ( ) 8 ( ) 7 ( ) | 1 ( ) 9 ( ) 2 ( ) | 5 ( ) 4 ( ) 6 ( ) | 1 ( ) 5 ( ) 2 ( ) | 6 ( ) 3 ( ) 4 ( ) | 7 ( ) 8 ( ){9}( ) | ============数独解题完成,尝试次数为:65============
总结
在写代码的过程中,研究案例,并且思考相关变化。
代码详情
代码地址
JAVA数独解题(五):X-wing(矩阵法)相关推荐
- JAVA数独解题(九):数链法(数串、垂直)
JAVA数独解题(九):数链法(数串.垂直) 说明 图片 算法代码 CalcEnum SuLianVerticalCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数独高 ...
- JAVA数独解题(一):框架搭建
JAVA数独解题(一):框架搭建 前言 环境 创建工程 实体类 Box Sudo 监听器 SudoListener SudoPrintImpl 核心类 SudoHandler 算法组 Abstract ...
- JAVA数独解题(四):数对法
JAVA数独解题(四):数对法 说明 图片 算法代码 CalcEnum SuDuiCalc SudoUtil 输出结果 总结 代码详情 说明 数对:两个单元格,两个数字.两个数字在当前区域(行.列.宫 ...
- JAVA数独解题(七):XYZ-wing
JAVA数独解题(七):XYZ-wing 说明 图片 算法代码 CalcEnum XYZwingCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数独高级技巧:XYZ-w ...
- 数据结构与算法Java(二)——字符串、矩阵压缩、递归、动态规划
不定期补充.修正.更新:欢迎大家讨论和指正 本文以数据结构(C语言版)第三版 李云清 杨庆红编著为主要参考资料,用Java来实现 数据结构与算法Java(一)--线性表 数据结构与算法Java(二)- ...
- java小球落体问题_[Java 编程基本功] (五) 小球落体, 发奖金, 1,2,3,4 可以组成多少个数...
[Java 编程基本功] (五) 小球落体, 发奖金, 1,2,3,4 可以组成多少个数 第十三题 一球从 100 米高度自由落下, 每次落地后反跳回原高度的一半; 再落下, 求它在第 10 次落地时 ...
- Python学习案例2——数独解题及出题程序
第二个求解案例,我想到了数独.曾经有一段时间对数独求解非常感兴趣,在学习C++语言时也编写了数独求解程序.本次Python学习,要求比之前高一点,把出题程序也一起编写了吧. 1.数独简介 数独 (英语 ...
- Java学习记录五(多线程、网络编程、Lambda表达式和接口组成更新)
Java学习记录五(多线程.网络编程.Lambda表达式和接口组成更新) Java 25.多线程 25.1实现多线程 25.1.1进程 25.1.2线程 25.1.3多线程的实现 25.1.4设置和获 ...
- Effective Java笔记第五章枚举和注解第三节用EnumSet代替位域
Effective Java笔记第五章枚举和注解 第三节用EnumSet代替位域 在以前如果一个枚举类型的元素主要用在集合中,一般就会使用int枚举模式.比如说: public class Demo ...
最新文章
- 产品经理技能树之 数据体系
- Django2.0——模板渲染(一)
- HDU4549 M斐波那契数列 —— 斐波那契、费马小定理、矩阵快速幂
- 三款ActiveX图表控件对比评测 TeeChart VS ProEssentials…
- eclipse 函数折叠展开
- 每日一题(46)—— volatile
- Linux 蓝牙读写,实战Linux Bluetooth编程(三) HCI层编程
- 【算法分析与设计】数组循环移位问题
- myeclipse2017安装与破解
- IPython高级用法(一)定制命令别名及存储别名
- 概率论:均值、标准差、方差、协方差、矩
- Mismatch between array dtype (‘<U40‘) and format specifier (‘%.18e‘)
- Java web 实战项目案例
- 430单片机实现三人投票表决器_基于单片机的五人表决器的设计
- 郭天祥老师单片机教程之串口练习题
- 激活windows 2008 r2
- react后台管理项目
- 计算机提示无法验证发布者,win10提示无法验证发布者所以windows已阻止此软件的解决方法【图文教程】...
- c语言打印日历的程序,简单日历打印(C语言)
- 可信平台模块TPM(Trusted Platform Module)介绍及tpm-tools安装使用