java暴力回朔法解数独

复制代码
BeginIndexRangeVO.java:
java 复制代码
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;


@Getter
@Setter
public class BeginIndexRangeVO implements Serializable {

    private int beginRowNum;
    private int beginColNum;

    public BeginIndexRangeVO(int beginRowNum, int beginColNum) {
        this.beginRowNum = beginRowNum;
        this.beginColNum = beginColNum;
    }
}
复制代码
PointVO.java:
java 复制代码
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.util.List;


@Getter
@Setter
public class PointVO implements Serializable {
    /*
        2  -  9    6  -  -    8  5  4
        4  8  6    9  5  2    7  3  1
        -  -  -    -  4  -    6  2  9

        -  -  2    4  -  9    5  8  6
        5  -  4    -  -  -    3  9  2
        -  9  -    2  -  5    1  4  7

        -  -  1    -  2  4    9  -  3
        9  4  -    3  1  -    2  -  5
        -  2  -    -  9  -    4  1  8
     */

    private String number;
    private String tryNumber;
    private int rowNum;
    private int colNum;
    private int gongNum=0;
    private String code;
    private List<String> possibleNumbers;
    private List<String> impossibleNumbers;
    private List<String> possibleNumbers_bak;

    public PointVO(String number, int rowNum, int colNum) {
        this.number = number;
        this.rowNum = rowNum;
        this.colNum = colNum;
    }

    public String getCode(){
        if( this.code != null ){
            return this.code;
        }
        this.code = this.rowNum + "-" + this.colNum;
        return this.code;
    }

    public int getGongNum(){
        if( this.gongNum > 0 ){
            return this.gongNum;
        }
        if( this.rowNum <= 3 ){
            if( this.colNum <= 3 ){
                this.gongNum = 1;
            }else if( this.colNum <= 6 ){
                this.gongNum = 2;
            }else {
                this.gongNum = 3;
            }
        }else if( this.rowNum <= 6 ){
            if( this.colNum <= 3 ){
                this.gongNum = 4;
            }else if( this.colNum <= 6 ){
                this.gongNum = 5;
            }else {
                this.gongNum = 6;
            }
        }else {
            if( this.colNum <= 3 ){
                this.gongNum = 7;
            }else if( this.colNum <= 6 ){
                this.gongNum = 8;
            }else {
                this.gongNum = 9;
            }
        }
        return this.gongNum;
    }
}
复制代码
RowColVO.java:
java 复制代码
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;


@Getter
@Setter
public class RowColVO implements Serializable {

    private int rowNum;
    private int colNum;

    public RowColVO(int rowNum, int colNum) {
        this.rowNum = rowNum;
        this.colNum = colNum;
    }
}
复制代码
ShuduSolver_backtracking.java:
java 复制代码
import java.util.*;


public class ShuduSolver_backtracking {
    private static final Map<Integer, BeginIndexRangeVO> map_gongNum_beginIndexRange = new HashMap<>();

    private static final Map<Integer,Set<String>> map_gongNum_numbers = new HashMap<>();
    private static final Map<Integer,Set<String>> map_rowNum_numbers = new HashMap<>();
    private static final Map<Integer,Set<String>> map_colNum_numbers = new HashMap<>();

    private static Map<String, PointVO> map_code_point;

    private static int deep_recursion = 0;

    private static int count_filled = 0;

    static {
        map_gongNum_beginIndexRange.put(1, new BeginIndexRangeVO(1, 1));
        map_gongNum_beginIndexRange.put(2, new BeginIndexRangeVO(1, 4));
        map_gongNum_beginIndexRange.put(3, new BeginIndexRangeVO(1, 7));

        map_gongNum_beginIndexRange.put(4, new BeginIndexRangeVO(4, 1));
        map_gongNum_beginIndexRange.put(5, new BeginIndexRangeVO(4, 4));
        map_gongNum_beginIndexRange.put(6, new BeginIndexRangeVO(4, 7));

        map_gongNum_beginIndexRange.put(7, new BeginIndexRangeVO(7, 1));
        map_gongNum_beginIndexRange.put(8, new BeginIndexRangeVO(7, 4));
        map_gongNum_beginIndexRange.put(9, new BeginIndexRangeVO(7, 7));
    }

    public static void main(String[] args) {
        int[][] chupan ={
                { 1,0,4,  0,0,0,  0,0,0 },
                { 0,0,0,  0,0,5,  0,0,0 },
                { 0,6,0,  0,8,0,  0,7,3 },

                { 0,0,0,  8,0,1,  9,0,0 },
                { 6,5,0,  0,0,0,  0,0,0 },
                { 0,0,0,  3,0,0,  0,0,8 },

                { 0,2,0,  0,3,0,  0,0,7 },
                { 0,0,0,  0,0,7,  1,3,0 },
                { 4,7,0,  0,0,0,  8,9,0 }
        };

        List<PointVO> points = initChuPan( chupan );
        map_code_point = points2CodeAndPointMap(points);

        init_map_xxxNum_numbers(  );
        print( );
        System.out.println("count_filled = " + count_filled);

        calculatePossibleNumbers();
        printPossibles();

        backtrackingAndCauseError();
        System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaa");
        printPossibles();
        print();
        System.out.println( "递归深度 = " + deep_recursion );
    }

    /**  ps:下一步填写全部的可能性都错了才表示上一步填错了
     * 发生错误,返回 true,
     * @return
     */
    private static boolean backtrackingAndCauseError() {
        deep_recursion++;
        // todo 找到第一个空格子
        PointVO point = searchFirstBlankPoint();
        if( point == null ){
            System.out.println( "222222222222222222222222222222222222" );
            System.out.println( "222222222222222222222222222222222222" );
            System.out.println( "222222222222222222222222222222222222" );
            System.out.println( "222222222222222222222222222222222222" );
            // 没有空格子了,表示游戏结束了
            System.exit( 0 );
        }
        int rowNum = point.getRowNum();
        int colNum = point.getColNum();
        String pointName = getPointName(rowNum, colNum);
        //  计算该格子可能填写的数字集合
        List<String> possibleNumbers = getPossibleNumbers( rowNum,colNum );
        if( possibleNumbers.size() == 0 ){
            //  该空格子不能填任何数字了,表示出现了错误
            return true;
        }
        possibleNumbers = deepCopyList( possibleNumbers );
        int count_possible = possibleNumbers.size();
        int count_error = 0;
        for( String possibleNumber:possibleNumbers ){
            fillNumber( rowNum,colNum,possibleNumber );
            boolean causeError = backtrackingAndCauseError();
            if( causeError ){
                count_error++;
            }
            clearNumber( rowNum,colNum,null );
        }
        if( count_error == count_possible ){
            // 该格子尝试全部的可能性都错,表示出现了错误
            return true;
        }
        return backtrackingAndCauseError();
    }

    private static PointVO searchFirstBlankPoint() {
        Set<String> codes = map_code_point.keySet();
        for( String code:codes ){
            PointVO point = map_code_point.get(code);
            if( point.getNumber() == null ){
                return point;
            }
        }
        return null;
    }

    private static void clearNumber(int rowNum, int colNum, String number) {
        String code = getCode(rowNum, colNum);
        PointVO point = map_code_point.get(code);
        point.setNumber( null );
        count_filled--;
        List<String> impossibleNumbers = point.getImpossibleNumbers();
        if( impossibleNumbers ==null ){
            impossibleNumbers = new ArrayList<>();
            point.setImpossibleNumbers( impossibleNumbers );
        }
        impossibleNumbers.add( number );

        // 初始化 当前格子所在的行、列、宫的 numers集合
        init_map_xxxNum_numbers( rowNum,colNum );
    }

    private static boolean gameSuccess(){
        return count_filled == 81;
    }

    private static String getPointName(int rowNum, int colNum) {
        return rowNum + "行" + colNum + "列";
    }

    /**
     * 初始化 当前格子所在的行、列、宫的 numers集合
     * @param targetRowNum
     * @param targetColNum
     */
    private static void init_map_xxxNum_numbers( int targetRowNum,int targetColNum ){
        //  行
        Set<String> numbers_currRow = map_rowNum_numbers.get(targetRowNum);
        numbers_currRow.clear();
        for (int colNum = 1; colNum <=9 ; colNum++) {
            String code = getCode(targetRowNum, colNum);
            PointVO point = map_code_point.get(code);
            if( point.getNumber() == null ){
                continue;
            }
            numbers_currRow.add( point.getNumber() );
        }

        //  列
        Set<String> numbers_currCol = map_colNum_numbers.get(targetColNum);
        numbers_currCol.clear();
        for (int rowNum = 1; rowNum <=9 ; rowNum++) {
            String code = getCode(rowNum, targetColNum);
            PointVO point = map_code_point.get(code);
            if( point.getNumber() == null ){
                continue;
            }
            numbers_currCol.add( point.getNumber() );
        }

        //  宫
        int gongNum = getGongNum(targetRowNum, targetColNum);
        Set<String> numbers_currGong = map_gongNum_numbers.get(gongNum);
        numbers_currGong.clear();
        BeginIndexRangeVO beginIndexRange = map_gongNum_beginIndexRange.get(gongNum);
        int beginRowNum = beginIndexRange.getBeginRowNum();
        int endRowNum = beginRowNum + 2;
        int beginColNum = beginIndexRange.getBeginColNum();
        int endColNum = beginColNum + 2;
        for (int rowNum = beginRowNum; rowNum <=endRowNum ; rowNum++) {
            for (int colNum = beginColNum; colNum <=endColNum ; colNum++) {
                String code = getCode(rowNum, colNum);
                PointVO point = map_code_point.get(code);
                if( point.getNumber() == null ){
                    continue;
                }
                numbers_currGong.add( point.getNumber() );
            }
        }
    }

    /**
     * 初始化三个缓存map( map_rowNum_numbers、map_colNum_numbers、map_gongNum_numbers )
     */
    private static void init_map_xxxNum_numbers( ) {
        //  1~9行
        for (int rowNum = 1; rowNum <=9 ; rowNum++) {
            Set<String> numbers_row = map_rowNum_numbers.get(rowNum);
            if( numbers_row == null ){
                numbers_row = new HashSet<>();
                map_rowNum_numbers.put( rowNum,numbers_row );
            }else {
                numbers_row.clear();
            }
            for (int colNum = 1; colNum <=9 ; colNum++) {
                String code = getCode(rowNum, colNum);
                PointVO point = map_code_point.get(code);
                if( point.getNumber() == null ){
                    continue;
                }
                numbers_row.add( point.getNumber() );
            }
        }

        //  1~9列
        for (int colNum = 1; colNum <=9 ; colNum++) {
            Set<String> numbers_col = map_colNum_numbers.get(colNum);
            if( numbers_col == null ){
                numbers_col = new HashSet<>();
                map_colNum_numbers.put( colNum,numbers_col );
            }else {
                numbers_col.clear();
            }
            for (int rowNum = 1; rowNum <=9 ; rowNum++) {
                String code = getCode(rowNum, colNum);
                PointVO point = map_code_point.get(code);
                if( point.getNumber() == null ){
                    continue;
                }
                numbers_col.add( point.getNumber() );
            }
        }

        //  1~9宫
        for (int gongNum = 1; gongNum <=9 ; gongNum++) {
            Set<String> numbers_gong = map_gongNum_numbers.get(gongNum);
            if( numbers_gong == null ){
                numbers_gong = new HashSet<>();
                map_gongNum_numbers.put( gongNum,numbers_gong );
            }else {
                numbers_gong.clear();
            }
            BeginIndexRangeVO beginIndexRange = map_gongNum_beginIndexRange.get(gongNum);
            int beginRowNum = beginIndexRange.getBeginRowNum();
            int endRowNum = beginRowNum + 2;
            int beginColNum = beginIndexRange.getBeginColNum();
            int endColNum = beginColNum + 2;
            for (int rowNum = beginRowNum; rowNum <=endRowNum ; rowNum++) {
                for (int colNum = beginColNum; colNum <=endColNum ; colNum++) {
                    String code = getCode(rowNum, colNum);
                    PointVO point = map_code_point.get(code);
                    if( point.getNumber() == null ){
                        continue;
                    }
                    numbers_gong.add( point.getNumber() );
                }
            }
        }
    }

    private static List<String> deepCopyList(List<String> list) {
        List<String> list_copy = new ArrayList<>();
        for( String item:list ){
            list_copy.add( item );
        }
        return list_copy;
    }

    private static void calculatePossibleNumbers( ) {
        for (int rowNum = 1; rowNum <=9 ; rowNum++) {
            for (int colNum = 1; colNum <=9 ; colNum++) {
                calculatePossibleNumberForTargetRowAndCol( rowNum,colNum );
            }
        }
    }

    private static List<String> getPossibleNumbers( int rowNum,int colNum ){
        String code = getCode(rowNum, colNum);
        PointVO point = map_code_point.get(code);

        Set<String> numbers_canNotFill = new HashSet<>();
        numbers_canNotFill.addAll( map_rowNum_numbers.get( rowNum ) );
        numbers_canNotFill.addAll( map_colNum_numbers.get( colNum ) );
        int gongNum = getGongNum( rowNum, colNum );
        numbers_canNotFill.addAll( map_gongNum_numbers.get(gongNum) );

        List<String> possibleNumbers = new ArrayList<>();
        for (int i = 1; i <=9 ; i++) {
            possibleNumbers.add( String.valueOf( i ) );
        }
        possibleNumbers.removeAll( numbers_canNotFill );
        if( point.getImpossibleNumbers() != null ){
            possibleNumbers.removeAll( point.getImpossibleNumbers() );
        }
        return possibleNumbers;
    }

    private static void calculatePossibleNumberForTargetRowAndCol(int targetRowNum, int targetColNum) {
        String code = getCode(targetRowNum, targetColNum);
        PointVO point = map_code_point.get(code);
        if( point.getNumber() != null ){
            return;
        }
        Set<String> numbers_canNotFill = new HashSet<>();
        numbers_canNotFill.addAll( map_rowNum_numbers.get(targetRowNum) );
        numbers_canNotFill.addAll( map_colNum_numbers.get(targetColNum) );
        int gongNum = getGongNum(targetRowNum, targetColNum);
        numbers_canNotFill.addAll( map_gongNum_numbers.get(gongNum) );

        List<String> numbers_possible = new ArrayList<>();
        for (int i = 1; i <=9 ; i++) {
            numbers_possible.add( String.valueOf( i ) );
        }
        numbers_possible.removeAll( numbers_canNotFill );

        if( point.getImpossibleNumbers() != null ){
            numbers_possible.removeAll( point.getImpossibleNumbers() );
        }

        point.setPossibleNumbers( numbers_possible );
        point.setPossibleNumbers_bak( deepCopyList( numbers_possible ) );
        point.setTryNumber( null );
    }

    private static String getSingleMissingNumber(Set<String> numbers) {
        if( numbers == null || numbers.size() != 8 ){
            return null;
        }
        int sum = 0;
        for( String number:numbers ){
            sum += Integer.valueOf( number );
        }
        // ps:45 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
        return String.valueOf( 45 - sum );
    }

    /**
     * 更新三个 map_xxxNum_numbers
     * @param rowNum
     * @param colNum
     * @param number
     */
    private static void addNumber2_map_xxxNum_numbers(int rowNum, int colNum, String number) {
        int gongNum = getGongNum(rowNum, colNum);
        map_gongNum_numbers.get( gongNum ).add( number );
        map_rowNum_numbers.get( rowNum ).add( number );
        map_colNum_numbers.get( colNum ).add( number );
    }

    private static void deleteNumberFrom_map_xxxNum_numbers(int rowNum, int colNum, String number) {

        init_map_xxxNum_numbers();
        int gongNum = getGongNum(rowNum, colNum);
        map_gongNum_numbers.get( gongNum ).remove( number );
        map_rowNum_numbers.get( rowNum ).remove( number );
        map_colNum_numbers.get( colNum ).remove( number );
    }

    private static void fillNumber(int rowNum, int colNum, String number) {
        System.out.println( "deep_recursion = " + deep_recursion );
        String code = getCode(rowNum, colNum);
        PointVO point = map_code_point.get(code);
        point.setNumber( number );
        count_filled++;
        if( gameSuccess() ){
            print();
            System.exit( 0 );
        }
        // 初始化 当前格子所在的行、列、宫的 numers集合
        init_map_xxxNum_numbers( rowNum,colNum );
    }

    /*
      -  2  -    4  -  9    1  -  -
      4  -  6    -  5  -    -  8  9
      -  7  -    -  8  3    -  2  4

      7  1  -    5  3  -    -  -  -
      -  -  -    -  9  -    2  -  -
      -  -  -    -  4  -    -  -  7

      -  6  -    -  -  -    -  -  -
      -  -  7    3  -  -    8  -  1
      3  4  -    -  -  5    -  6  -
   */
    private static int getGongNum(int rowNum, int colNum) {
        if( rowNum <= 3 ){
            if( colNum <= 3 ){
                return 1;
            }else if( colNum <= 6 ){
                return 2;
            }else {
                return 3;
            }
        }else if( rowNum <= 6 ){
            if( colNum <= 3 ){
                return 4;
            }else if( colNum <= 6 ){
                return 5;
            }else {
                return 6;
            }
        }else {
            if( colNum <= 3 ){
                return 7;
            }else if( colNum <= 6 ){
                return 8;
            }else {
                return 9;
            }
        }
    }

    private static String getCode(int rowNum, int colNum) {
        return rowNum + "-" + colNum;
    }

    public static  Map<String, PointVO> points2CodeAndPointMap( List<PointVO> points ){
        Map<String, PointVO> map_code_point = new HashMap<>();
        for( PointVO point:points ){
            map_code_point.put( point.getCode(),point );
        }
        return map_code_point;
    }

    public static void print( ){
        System.out.println();
        System.out.println( "--------------------------------------------------------------------------------------" );
        for (int rowNum = 1; rowNum <=9 ; rowNum++) {
            for (int colNum = 1; colNum <=9 ; colNum++) {
                String code = getCode( rowNum,colNum );
                PointVO point = map_code_point.get(code);
                if( point.getNumber() == null ){
                    System.out.print( "-"  + "  ");
                }else {
                    System.out.print( point.getNumber()  + "  ");
                }
                if( colNum % 3 == 0 ){
                    System.out.print("  ");
                }
            }
            System.out.println();
            if( rowNum % 3 ==0 ){
                System.out.println();
            }
        }
    }

    public static void printPossibles( ){
        System.out.println();
        System.out.println( "--------------------------------------------------------------------------------------" );
        Map<Integer, Integer> map_colNum_maxLen = new HashMap<>();
        for (int colNum = 1; colNum <=9; colNum++) {
            int maxLen = 1;
            for (int rowNum = 1; rowNum <=9 ; rowNum++) {
                String code = getCode(rowNum, colNum);
                PointVO point = map_code_point.get(code);
                if( point.getNumber() != null ){
                    continue;
                }
                List<String> possibleNumbers = point.getPossibleNumbers();
                if( possibleNumbers.size() > maxLen ){
                    maxLen = possibleNumbers.size();
                }
            }
            maxLen+=2;
            map_colNum_maxLen.put( colNum,maxLen );
        }

        for (int rowNum = 1; rowNum <=9 ; rowNum++) {
            for (int colNum = 1; colNum <=9 ; colNum++) {
                String code = getCode( rowNum,colNum );
                PointVO point = map_code_point.get(code);
                String value = null;
                if( point.getNumber() == null ){
                    value = "[" + getStickTogetherFormat( point.getPossibleNumbers() ) + "]";
                }else {
                    value = point.getNumber();
                }
                int maxLen = map_colNum_maxLen.get( colNum );
                if( value.length() < maxLen ){
                    value += getBlank( maxLen - value.length() );
                }
                System.out.print( value  + "  ");
                if( colNum % 3 == 0 ){
                    System.out.print("    ");
                }
            }
            System.out.println();
            if( rowNum % 3 ==0 ){
                System.out.println();
                System.out.println();
            }
        }
    }

    private static String getBlank(int count) {
        String blank = "";
        for (int i = 0; i < count; i++) {
            blank += " ";
        }
        return blank;
    }

    private static String getStickTogetherFormat(List<String> list) {
        if( list == null || list.size() == 0 ){
            return "";
        }
        String str = "";
        for( String item:list ){
            str += item;
        }
        return str;
    }

    public static List<PointVO> initChuPan(int[][] chupan) {
        List<PointVO> points = new ArrayList<>();
        for (int rowNum = 0; rowNum < 9; rowNum++) {
            int[] row = chupan[rowNum];
            for (int colNum = 0; colNum <9 ; colNum++) {
                int number = row[colNum];
                String number_str = null;
                if( number > 0 && number < 10 ){
                    count_filled++;
                    number_str = String.valueOf( number );
                }
                points.add( new PointVO(number_str,rowNum+1,colNum+1 ) );
            }
        }
        return points;
    }
}
相关推荐
秃头佛爷1 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
阿伟*rui1 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
待磨的钝刨1 小时前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck3 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei3 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师4 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉4 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer4 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq4 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端