首页 > 试题广场 >

Sudoku

[编程题]Sudoku
  • 热度指数:85013 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
问题描述:数独(Sudoku)是一款大众喜爱的数字逻辑游戏。玩家需要根据9X9盘面上的已知数字,推算出所有剩余空格的数字,并且满足每一行、每一列、每一个3X3粗线宫内的数字均含1-9,并且不重复。
例如:
输入

输出


数据范围:输入一个 9*9 的矩阵

输入描述:

包含已知数字的9X9盘面数组[空缺位以数字0表示]



输出描述:

完整的9X9盘面数组

示例1

输入

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

输出

5 9 2 4 8 1 7 6 3
4 1 3 7 6 2 9 8 5
8 6 7 3 5 9 4 1 2
6 2 4 1 9 5 3 7 8
7 5 9 8 4 3 1 2 6
1 3 8 6 2 7 5 9 4
2 7 1 5 3 8 6 4 9
3 8 6 9 1 4 2 5 7
9 4 5 2 7 6 8 3 1
回溯算法
import java.util.*;
public class Main {
    public static int[][] sudo = new int[9][9];//创建数组
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            for(int i=0;i<9;i++){
                for(int j=0;j<9;j++){
                    sudo[i][j]=sc.nextInt();//创建数独
                }
            }
            if(backTracking(sudo)){
                for(int i=0;i<9;i++){
                    for(int j=0;j<9;j++){
                        if(j==8){
                            //最后一位数需要换行输出
                            System.out.println(sudo[i][j]);
                        }else{
                            System.out.print(sudo[i][j]+" ");
                        }
                    }
                }
            }
        }

    }
    public static boolean backTracking(int[][] sudo){
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){//遍历数组
                if(sudo[i][j]!=0){//如果不需要填数字直接continue
                    continue;
                }
                for(int k=1;k<=9;k++){//循环填数字
                    if(isValid(i,j,k,sudo)){//判断填入数字是否符合要求
                        sudo[i][j]=k;//填数字
                        if(backTracking(sudo)){//递归
                            return true;
                        }
                        sudo[i][j]=0;//回溯
                    }
                }
                return false;//如果没有符合要求的数字返回false
            }
        }
        return true;
    }
    public static boolean isValid(int row,int col,int k,int[][] sudo){
        for(int i=0;i<9;i++){//检查行
            if(sudo[row][i]==k){
                return false;
            }
        }
        for(int i=0;i<9;i++){//检查列
            if(sudo[i][col]==k){
                return false;
            }
        }
        int startRow = (row/3)*3;
        int endCol = (col/3)*3;
        for(int i=startRow;i<startRow+3;i++){//检查九宫格
            for(int j=endCol;j<endCol+3;j++){
                if(sudo[i][j]==k){
                    return false;
                }
            }
        }
        return true;
    }
}


发表于 2022-07-29 15:49:37 回复(0)
回溯、检查每行每列,还要记住检查3*3格子 ,答案多种不唯一不影响AC

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        int[][] numbers = new int[9][9];
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        int[][] indexs = new int[81][2];
        int nextRow = 0;
        char c;
        for (int i = 0, j = 0; j < 9; ) {
            c = (char) in.read();
            if (c == ' ') continue;

            if (c == '\n' || c == '\r') {
                j++;
                i = 0;
                continue;
            }
            numbers[j][i] = Integer.valueOf(c + "");
            if (numbers[j][i] == 0) {
                indexs[nextRow][0] = j;
                indexs[nextRow][1] = i;
                nextRow++;
            }
            i++;
        }

        int num;
        boolean isOK;
        int[] vals;
        int m, n;
        for (int i = 0; i < nextRow; ) {
            num = numbers[indexs[i][0]][indexs[i][1]];
            numbers[indexs[i][0]][indexs[i][1]] = 0;

            vals = new int[10];
            for (int j = 0; j < 9; j++) {
                vals[numbers[indexs[i][0]][j]] = 1;
            }

            for (int j = 1; j < 10; j++) {
                if (vals[j] == 0 && num < j) {
                    isOK = true;
                    for (int k = 0; k < 9; k++) {
                        //横列
                        if (j == numbers[indexs[i][0]][k]) {
                            isOK = false;
                            break;
                        }
                        //竖列
                        if (j == numbers[k][indexs[i][1]]) {
                            isOK = false;
                            break;
                        }
                        //粗线框要唯一!!!
                        //粗线框要唯一!!!
                        //粗线框要唯一!!!
                        //0:00, 1:01, 2:02
                        //4:10, 5:11, 6:12
                        //7:20, 8:21, 9:22

                        m = k / 3 + (indexs[i][0] / 3) * 3;
                        n = k % 3 + (indexs[i][1] / 3) * 3;
                        if (j == numbers[m][n]) {
                            isOK = false;
                            break;
                        }
                    }
                    if (isOK) {
                        numbers[indexs[i][0]][indexs[i][1]] = j;
                        break;
                    }
                }
            }
            if (numbers[indexs[i][0]][indexs[i][1]] == 0) {
                i--;//回溯
            } else {
                i++;
            }
        }

        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                sb.append(numbers[i][j]);
                sb.append(" ");
            }
            sb.append("\n");
        }
        sb.delete(sb.length() - 1, sb.length());
        System.out.println(sb);
    }
}






编辑于 2021-02-25 18:51:48 回复(0)
来个C的:

#include<stdio.h>

#define N 9
#define MOD 3

int is_valid(int (*p)[N], int row, int col) {
    int check[N + 1] = {0};
    for (int i = 0; i < N + 1; i++) check[i] = 1;
    for (int i = 0; i < N; i++) {
        if (check[p[row][i]])
            check[p[row][i]] = 0;
        else if (p[row][i] != 0)
            return 0;
    }

    for (int i = 0; i < N + 1; i++) check[i] = 1;
    for (int i = 0; i < N; i++) {
        if (check[p[i][col]])
            check[p[i][col]] = 0;
        else if (p[i][col] != 0)
            return 0;
    }

    for (int i = 0; i < N + 1; i++) check[i] = 1;
    int r0 = row - row % MOD;
    int c0 = col - col % MOD;
    for (int k = 0; k < N; k++) {
        int r = r0 + k / MOD;
        int c = c0 + k % MOD;
        if (check[p[r][c]])
            check[p[r][c]] = 0;
        else if (p[r][c] != 0)
            return 0;
    }
    return 1;
}

int sudoku(int (*p)[N], int depth) {
    if (depth == 0) {
        return 0;
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (p[i][j] == 0) {
                for (int k = 1; k <= N + 1; k++) {
                    if (k == N + 1)
                        return depth;
                    p[i][j] = k;
                    if (is_valid(p, i, j)) {
                        depth--;
                        depth = sudoku(p, depth);
                        if (depth == 0)
                            return 0;
                        depth++;
                    }
                    p[i][j] = 0;
                }
            }
        }
    }
    return depth;
}

int main() {
    int a[N][N] = {0};
    int depth = 0;

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            scanf("%d", &a[i][j]);
            if (a[i][j] == 0) depth++;
        }
    }

    sudoku(a, depth);

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            printf((j == N - 1) ? "%d\n" : "%d ", a[i][j]);
        }
    }
    return 0;
}


发表于 2021-01-10 11:25:59 回复(0)
a = []

def check(row, col, v):#传入位置和这个元素
    for k in range(9):#判断,如果在这一行或者这一列里面以及有元素等于v了,就返回false
        if a[row][k] == v&nbs***bsp;a[k][col] == v: return False
    t = row//3#把9×9的转变为9个3×三的小矩阵
    q = col//3
    for k in range(t*3,t*3+3):#判断这个小矩阵,看这个小矩阵里面是否有元素等于这个数,如果有,就返回false!为什么判断这个呢??哦,题目要求了,这个小的矩形也不能重复的
        for p in range(q*3,q*3+3):
            if a[k][p] == v: return False
    return True

def f(num):#不断的判断,某个位置是否能够填这个数。
    global a
    if num > 80: return True#大于80,说明全部扫完了。
    row = num // 9#行数,行数和列数是变化的。明显列数变化的比行快一些
    col = num % 9#列数
    if a[row][col] != 0: return f(num+1)#不等于0,说明这个地方有数,占住了位子
    else:#否则,就是等于0,需要考虑填什么数合适
        for i in range(1,10):
            if check(row,col,i): #检查,这个位置填i可以吗,如果可以则填
                a[row][col] = i
                if f(num+1): return True
                else: a[row][col] = 0
        return False

while True:
    try:
        for i in range(9):
            b = list(map(int,input().split()))
            a.append(b)
        f(0)
        for i in range(9):
            print(' '.join(map(str,a[i])))
    except:
        break
批注了一下,便于理解这一段代码,排第一的python解法
发表于 2020-08-13 21:16:55 回复(1)
def check(sod,loc,value):
    x, y = loc//9,loc%9
    row = sod[x]
    column = list(b[y] for b in sod)
    x1,y1 = (x//3)*3,(y//3)*3
    L1,L2,L3 = sod[x1][y1:y1+3],sod[x1+1][y1:y1+3],sod[x1+2][y1:y1+3]
    matrix = L1+L2+L3
    allnum = row+column+matrix+[0]
    if value in allnum:
        return False
    else:
        return True

def solver(sodoku:list):
    total = []
    def search(sodo:list,nowloc=0):
        if nowloc == 81:
            for i in sodo:
                print(' '.join(list(map(str,i))))
            return True
        x, y = nowloc//9,nowloc%9
        if sodo[x][y] == 0:
            for i in range(1,10,1):
                if check(sodo,nowloc,i):
                    sodo[x][y] = i
                    if search(sodo,nowloc+1):
                        return True
                    else:
                        sodo[x][y] = 0
            return False
        else:
            search(sodo,nowloc+1)
        return False
    search(sodoku,0)
    return total
for i in range(1):
    try:
        mylist = []
        for i in range(9):
            mylist.append(list(map(int,input().split())))
        solver(mylist)
    except:
        break
        
题目不完整,缺少粗线框的限制
发表于 2020-05-01 17:04:33 回复(0)

import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.IntStream;

public class Main {

    private static int BOARD_SIZE = 9;
    private static int SUBSECTION_SIZE = 3;
    private static int NO_VALUE = 0;
    private static int MIN_VALUE = 1;
    private static int MAX_VALUE = 9;
    private static int BOARD_START_INDEX = 0;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[][] bc = new int[9][9];
        while (sc.hasNextLine()) {
            for (int i = 0; i < 9; i++) {
                String str = sc.nextLine();
                String[] ss = str.split(" ");
                for (int j = 0; j < 9; j++) {
                    bc[i][j] = Integer.parseInt(ss[j]);
                }
            }
            solve(bc);
            printBoard(bc);
        }
    }

    private static boolean isValid(int[][] board, int row, int column) {
        return (rowConstraint(board, row) && columnConstraint(board, column)
                && subsectionConstraint(board, row, column));
    }

    private static boolean rowConstraint(int[][] board, int row) {
        boolean[] constraint = new boolean[BOARD_SIZE];
        return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
                .allMatch(column -> checkConstraint(board, row, constraint, column));
    }

    private static boolean columnConstraint(int[][] board, int column) {
        boolean[] constraint = new boolean[BOARD_SIZE];
        return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
                .allMatch(row -> checkConstraint(board, row, constraint, column));
    }

    private static boolean subsectionConstraint(int[][] board, int row, int column) {
        boolean[] constraint = new boolean[BOARD_SIZE];
        int subsectionRowStart = (row / SUBSECTION_SIZE) * SUBSECTION_SIZE;
        int subsectionRowEnd = subsectionRowStart + SUBSECTION_SIZE;

        int subsectionColumnStart = (column / SUBSECTION_SIZE) * SUBSECTION_SIZE;
        int subsectionColumnEnd = subsectionColumnStart + SUBSECTION_SIZE;

        for (int r = subsectionRowStart; r < subsectionRowEnd; r++) {
            for (int c = subsectionColumnStart; c < subsectionColumnEnd; c++) {
                if (!checkConstraint(board, r, constraint, c))
                    return false;
            }
        }
        return true;
    }

    private static boolean checkConstraint(int[][] board, int row, boolean[] constraint, int column) {
        if (board[row][column] != NO_VALUE) {
            if (!constraint[board[row][column] - 1]) {
                constraint[board[row][column] - 1] = true;
            } else {
                return false;
            }
        }
        return true;
    }

    private static void printBoard(int[][] board) {
        for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
            
            System.out.println(Arrays.toString(board[row]).replaceAll("[,\\[\\]]", ""));
        }
    }

    private static boolean solve(int[][] board) {
        for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
            for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
                if (board[row][column] == NO_VALUE) {
                    for (int k = MIN_VALUE; k <= MAX_VALUE; k++) {
                        board[row][column] = k;
                        if (isValid(board, row, column) && solve(board)) {
                            return true;
                        }
                        board[row][column] = NO_VALUE;
                    }
                    return false;
                }
            }
        }
        return true;
    }
}
case通过率为83.33%
发表于 2019-12-30 23:09:48 回复(0)
    
def try_on(x,y): 
    #print(x,y)
    hadnum=[]
    for n in range(9):
        hadnum.append(matrix[x][n])
        hadnum.append(matrix[n][y])
    for n in range(3):
        for m in range(3):
            hadnum.append(matrix[x/3*3+n][y/3*3+m])

    restnum=[]
    for n in range(1,10):
        if n not in hadnum:
            restnum.append(n)
    #print(hadnum,restnum)
    
    for n in restnum:
        matrix[x][y]=n
        nx,ny,fd=-1,-1,0
        for xx in range(9):
            for yy in range(9):
                if matrix[xx][yy]==0:
                    nx=xx
                    ny=yy
                    fd=1
                    break
            if fd==1:
                break
        if nx==-1:
            return True
        #print(x,y,n,nx,ny)
        if try_on(nx,ny)==True:
            matrix[x][y]=n
            return True
        else:
            matrix[x][y]=0
    
    return False

try:
    while True:
        matrix=[]
        for n in range(9):
            matrix.append([int(n) for n in raw_input().split()])
        nx,ny,fd=-1,-1,0
        for xx in range(9):
            for yy in range(9):
                if matrix[xx][yy]==0:
                    nx=xx
                    ny=yy
                    fd=1
                    break
            if fd==1:
                break
        try_on(nx,ny)
        msg=""
        for l in matrix:
            for n in l:
                msg=msg+"%d "%n
            msg=msg.strip()+"\n"
        print(msg[:-1])

except:
    pass


都没几个人用python,这让我很蛋疼啊

发表于 2017-03-15 14:00:20 回复(1)
这题答案不唯一的。系统给的答案:
我的代码测出的答案:
代码如下:
#include <iostream>  
using namespace std; 
      
bool sign = false;    
int num[9][9]; 
     
void Output() 
{   
    for (int i = 0; i < 9; i++){ 
        for (int j = 0; j < 8; j++) 
            cout << num[i][j] << " "; 
        cout << num[i][8]; 
        cout << endl; 
    } 
}
 
/* 判断key填入n格时是否满足条件,n代表第几个格子 */ 
bool Check(int n, int key) 
{ 
    /* 判断n所在横列是否合法 */ 
    for (int i = 0; i < 9; i++){ 
        /* j为n竖坐标 */ 
        int j = n / 9; 
        if (num[j][i] == key)
            return false; 
    } 
    
    /* 判断n所在竖列是否合法 */ 
    for (int i = 0; i < 9; i++){ 
        /* j为n横坐标 */ 
        int j = n % 9; 
        if (num[i][j] == key)
            return false; 
    } 
    
    int y = n / 9 / 3 * 3; 
    int x = n % 9 / 3 * 3;     
    /* 判断n所在的小九宫格是否合法 */ 
    for (int i = y; i < y + 3; i++)  
        for (int j = x; j < x + 3; j++) 
            if (num[i][j] == key)
                return false; 

    return true; 
} 
 
/* 深搜 */ 
int DFS(int n) 
{ 
    /* 所有的都符合,退出搜索,n代表格子数,共81个格子,0~80 */ 
    if (n > 80){ 
        sign = true; 
        return 0; 
    } 

    if (num[n / 9][n % 9] != 0) 
        DFS(n + 1);  
    else{ 
        /* 否则对当前位一次填入1~9进行测试 */ 
        for (int i = 1; i <= 9; i++){ 
            if (Check(n, i)){ 
                num[n / 9][n % 9] = i; 
                /* 继续搜索,后续位也填1~9测试,直到最后一位,通过的话置true */ 
                DFS(n + 1); 
                /* 返回时如果构造成功,则直接退出 */ 
                if (sign)  
                    return 0; 
                /* 如果构造不成功,还原当前位 */ 
                num[n/9][n%9] = 0;
            }
                  
        } 
    }
    return 0;
} 
      
int main() 
{  
    for (int i = 0; i < 9; i++){
        for (int j = 0; j < 9; j++)
            cin >> num[i][j]; 
    }
    DFS(0);     //从第0格开始填 
    Output(); 
}

编辑于 2016-06-04 14:25:49 回复(18)
#-*- coding: utf8 -*-

def check(matrix,row,col,value):
    """
    检测在(row,col)放value是否合适
    1.每行含1-9,不含重复值value
    2.每列含1-9,不含重复值value
    3.3*3区块含1-9,不含重复值value
    """
    #检测每行
    for j in range(9):
        if matrix[row][j]==value:
            return False
    #检测每列
    for i in range(9):
        if matrix[i][col]==value:
            return False
    #检测元素所在3*3区域
    area_row=(row/3)*3
    area_col=(col/3)*3
    for i in range(area_row,area_row+3):
        for j in range(area_col,area_col+3):
            if matrix[i][j]==value:
                return False
    return True

def solveSudoku(matrix,count=0):
    """
    遍历每一个未填元素,遍历1-9替换为合适的数字
    """
    if (count==81):#递归出口
        return True
    row=count/9#行标
    col=count%9#列标
    if (matrix[row][col]!=0):#已填充
        return solveSudoku(matrix,count=count+1)
    else:#未填充
        for i in range(1,10):
            if check(matrix,row,col,i):#找到可能的填充数
                matrix[row][col]=i
                if solveSudoku(matrix,count=count+1):#是否可完成
                    return True#可完成
                #不可完成
                matrix[row][col]=0#回溯
        return False#不可完成

matrix=[]
for i in range(9):
    matrix.append(map(int,raw_input().split(' ')))
solveSudoku(matrix)
for i in range(9):
    print ' '.join(map(str,matrix[i]))

发表于 2018-07-11 15:03:29 回复(1)
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[][] matrix = new int[9][9];
        while (sc.hasNext()) {
            for (int i = 0; i < 9; i ++) {
                for (int j = 0; j < 9; j ++) {
                    matrix[i][j] = sc.nextInt();
                }
            }
            sudoku(matrix, 0, 0);
            for (int i = 0; i < 9; i ++) {
                for (int j = 0; j < 9; j ++) {
                    if(j == 8) System.out.println(matrix[i][j]);
                    else System.out.print(matrix[i][j] + " ");
                }
            }
        }
    }
    public static boolean sudoku(int[][] matrix, int i, int j) {
        if(i > 8) return true;
        if(matrix[i][j] != 0) {
            if(j < 8 && sudoku(matrix, i, j + 1)) return true; // 未到行位,求解同行下一个
            else if(j >= 8 && sudoku(matrix, i + 1, 0)) return true; // 已到行位,求解下一行第一个
        } else {
            for (int num = 1; num <= 9; num ++) {
                if(check(matrix, i, j, num)) {
                    matrix[i][j] = num;
                    if(j < 8 && sudoku(matrix, i, j + 1)) return true;
                    else if(j >= 8 && sudoku(matrix, i + 1, 0)) return true;
                    matrix[i][j] = 0; // 回溯
                }
            }
        }
        return false;
    }
    // 检查行、列、3*3格
    public static boolean check(int[][] matrix, int i, int j, int num) {
        if(check_row(matrix, i, j, num) && check_col(matrix, i, j, num) && check_3_by_3(matrix, i, j, num)) return true;
        return false;
    }
    // 检查所在行
    public static boolean check_row(int[][] matrix, int i, int j, int num) {
        for (int k = 0; k < 9; k ++) {
            if(matrix[i][k] == num) return false;
        }
        return true;
    }
    // 检查所在列
    public static boolean check_col(int[][] matrix, int i, int j, int num) {
        for (int k = 0; k < 9; k ++) {
            if(matrix[k][j] == num) return false;
        }
        return true;
    }
    // 检查所在3*3格
    public static boolean check_3_by_3(int[][] matrix, int i, int j, int num) {
        int row_from = i / 3 * 3;
        int row_to = row_from + 2;
        int col_from = j / 3 * 3;
        int col_to = col_from + 2;
        for (int x = row_from; x <= row_to; x ++) {
            for (int y = col_from; y <= col_to; y ++) {
                if(matrix[x][y] == num) return false;
            }
        }
        return true;
    }
}

发表于 2017-11-24 18:18:16 回复(0)
def value(x, y):
    i, j = x // 3, y // 3
    grid = [m[i * 3 + r][j * 3 + c] for r in range(3) for c in range(3)]
    row_val = m[x]
    col_val = list(zip(*m))[y]
    return {1, 2, 3, 4, 5, 6, 7, 8, 9} - set(grid) - set(row_val) - set(col_val)


def sudoku(pos):
    if not pos:  # 填完了
        res.append([' '.join(map(str, i)) for i in m])
    else:
        x, y = pos[0]
        val = value(x, y)
        if val:
            for v in val:
                m[x][y] = v
                sudoku(pos[1:])
                m[x][y] = 0  # 回溯

m = [list(map(int, input().split())) for i in range(9)]
pos = [(x, y) for y in range(9) for x in range(9) if not m[x][y]]
res = []
sudoku(pos)
print('\n'.join(res[0]))

发表于 2023-05-06 10:40:03 回复(0)
import java.util.Scanner;

/**
 * dfs解数独
 * 从左往右,从上往下遍历每个格子
 * 在空格处 循环1-9,检查能不能放,能放->放入,继续递归。不能放->回溯到上一个空格
 * 当最后一行遍历完了,说明格子都填满了,直接结束。
 */
public class Main {
    //定义数独数组,9行9列
    public static int[][] arr = new int[9][9];
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextInt()){
            //初始化数独数组
            for (int i = 0;i < 9;i++){
                for (int j = 0; j < 9;j++){
                    arr[i][j] = sc.nextInt();
                }
            }
            //调用dfs方法
            dfs(0,0);
            //打印结果
            for (int i = 0;i < 9;i++){
                for (int j = 0; j < 9;j++){
                    System.out.print(arr[i][j]+" ");
                }
                System.out.println();
            }
        }
    }

    /**
     * dfs填数独
     * @param x 当前的行
     * @param y 当前的列
     * @return
     */
    public static boolean dfs(int x,int y){
        //x的范围是0-8,如果x到9,说明数组已经全填完了,直接结束,返回true
        if (x == 9){
            return true;
        }
        //y的范围是0-8,如果到9,说明当前行已经遍历完所有列了,跳到下一行
        if (y == 9){
            return dfs(x+1,0);
        }
        //当前格子已经填了数字了,跳到下一个格子
        if (arr[x][y] != 0){
            return dfs(x,y+1);
        }
        //走到这一步说明当前这个格子是空的,还要判断一下是否能填数字
        //循环1-9
        for (int i = 1;i <= 9;i++){
            //当前格子能填数字i
            if (check(x,y,i)){
                //填上
                arr[x][y] = i;
                //继续递归,如果能成功,返回true
                if (dfs(x,y+1)){
                    return true;
                }
                //如果走到这一步,说明后面的某个格子填入失败了,回溯到这一步,把当前格子改回空格,继续循环
                arr[x][y] = 0;
            }
        }
        //如果循环完了没有数字能填入,结束当前dfs,返回false
        return false;
    }

    /**
     * 检查当前这个格子能不能填数字num
     * @param x 当前行
     * @param y 当前列
     * @param num 准备填入的数字
     * @return
     */
    public static boolean check(int x ,int y , int num){
        //循环遍历,拿传入的数字与每行,每列比较
        for (int i = 0;i < 9 ;i++){
            //与当前行其他数字比较
            if (arr[x][i] == num){
                return false;
            }
            //与当前列其他数字比较
            if (arr[i][y] == num){
                return false;
            }
        }
        //循环遍历,那传入的数字与每个小九宫格里的数字比较
        for (int i = (x/3)*3;i < (x/3)*3+3 ; i++){
            for (int j = (y/3)*3; j < (y/3)*3+3;j++){
                if (arr[i][j] == num){
                    return false;
                }
            }
        }
        return true;
    }
}

发表于 2021-12-04 17:19:08 回复(2)
LeetCode 037,经典的NP问题,采用Dancing Links可以优化算法
参考:http://www.cnblogs.com/tonyluis/p/4488727.html
DFS算法如下(测试用例答案不唯一):
import java.util.*;

public class Main {

	public static void main(String[] args) {
		int[][] board = new int[9][9];
		Scanner in = new Scanner(System.in);
		for (int i = 0; i < board[0].length; i++)
			for (int j = 0; j < board.length; j++)
				board[i][j] = in.nextInt();
		in.close();
		solveSudoku(board);
		for (int i = 0; i < board[0].length; i++) {
			for (int j = 0; j < board.length - 1; j++)
				System.out.print(board[i][j] + " ");
			System.out.println(board[i][board.length - 1]);
		}

	}

	static int solveSudoku(int[][] board) {
		int depth = 0;
		for (int i[] : board)
			for (int j : i)
				if (j == 0)
					depth++;
		return dfs(board, depth);
	}

	static int dfs(int[][] board, int depth) {
		if (depth == 0)
			return 0;
		for (int i = 0; i < board.length; i++) {
			for (int j = 0; j < board[0].length; j++) {
				if (board[i][j] == 0) {
					for (int k = 1; k <= 10; k++) {
						if (k == 10)
							return depth;
						board[i][j] = k;
						if (!isValid(board, i, j))
							board[i][j] = 0;
						else {
							depth--;
							depth = dfs(board, depth);
							if (depth == 0)
								return depth;
							depth++;
							board[i][j] = 0;
						}
					}
				}
			}
		}
		return depth;
	}

	static boolean isValid(int[][] board, int row, int col) {
		boolean[] check = new boolean[10];
		for (int i = 0; i < check.length; i++)
			check[i] = true;
		for (int i = 0; i < board[0].length; i++) {
			if (check[board[row][i]])
				check[board[row][i]] = false;
			else if (board[row][i] != 0)
				return false;
		}

		for (int i = 0; i < check.length; i++)
			check[i] = true;
		for (int i = 0; i < board.length; i++) {
			if (check[board[i][col]])
				check[board[i][col]] = false;
			else if (board[i][col] != 0)
				return false;
		}

		for (int i = 0; i < check.length; i++)
			check[i] = true;
		int rowTemp = (row / 3) * 3;
		int colTemp = (col / 3) * 3;
		for (int k = 0; k < 9; k++) {
			row = rowTemp + k / 3;
			col = colTemp + k % 3;
			if (check[board[row][col]])
				check[board[row][col]] = false;
			else if (board[row][col] != 0)
				return false;
		}
		return true;
	}
}
编辑于 2016-08-05 10:37:39 回复(1)
java 建立行约束、列约束、方格约束,同时记录空缺位置进行回溯
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    // 记录每行 每列 每个方格该位置的元素是否出现
    private static boolean[][] row;
    private static boolean[][] col;
    private static boolean[][][] board;
    private static int[][] matrix = new int[9][9];
    private static boolean flag = false;
    
    // 空缺列表
    private static List<int[]> list;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextInt()) { // 注意 while 处理多个 case
            for(int i=0;i<9;i++){
                for(int j=0;j<9;j++){
                    matrix[i][j] = in.nextInt();
                }
            }
            row = new boolean[9][10];
            col = new boolean[9][10];
            board = new boolean[3][3][10];
            list =  new ArrayList<>();
            for(int i=0;i<9;i++){
                for(int j=0;j<9;j++){
                    if(matrix[i][j] == 0){
                        list.add(new int[]{i,j});
                        continue;
                    }
                    // 记录该元素已经在该行 该列 该单元格出现
                    row[i][matrix[i][j]] = col[j][matrix[i][j]] = board[i/3][j/3][matrix[i][j]] = true;
                }
                
            }
            dfs(0);
            for(int i=0;i<9;i++){
                for(int j=0;j<9;j++){
                    System.out.print(matrix[i][j]);
                    if(j < 8) System.out.print(" ");
                }
                System.out.println();
            }
        }
    }
    
    // 回溯
    public static void dfs(int cnt){
        if(cnt == list.size()){
            flag = true;
            return ;
        }
        int[] cur = list.get(cnt);
        int i = cur[0], j = cur[1];
        for(int digit=1;digit<=9 && !flag;digit++){ // 枚举(i,j)填写的数字
            if(!row[i][digit] && !col[j][digit] && !board[i/3][j/3][digit]){
                row[i][digit] = col[j][digit] = board[i/3][j/3][digit] = true;
                // 将数组中该位置的元素改为digit
                matrix[i][j] = digit;
                dfs(cnt+1);
                //matrix[i][j] = 0;
                row[i][digit] = col[j][digit] = board[i/3][j/3][digit] = false;
            }
        }
    }
}


发表于 2022-06-20 11:23:51 回复(0)

这个人太笨了,写了一百行

#include <iostream>  
#include<vector>
using namespace std; 
      
class Sudoku{
private:
    vector<vector<int>> sudoku;
public:
    Sudoku()
    {
        sudoku.resize(9, vector<int>(9));
        for(int i = 0; i < 9; ++i)
        {
            for(int j = 0; j < 9; ++j)
                cin >> sudoku[i][j];
        }
    };

    bool sudokuCheck(int i, int j, int n)
    {
        for(int p = 0; p < 9; ++p)
        {
            if (this->sudoku[i][p] == n)
                return false;
            if (this->sudoku[p][j] == n)
                return false;
        }

        int ii = (int)(i / 3) * 3;
        int jj = (int)(j / 3) * 3;
        for(int p = 0; p < 3; ++p)
        {
            for(int q = 0; q < 3; ++q)
            {
                if (this->sudoku[ii + p][jj + q] == n)
                    return false;
            }
        }

        return true;
    }

    bool sudokuCkeckDFS()
    {
        for(int i = 0; i < 9; ++i)
        {
            for(int j = 0; j < 9; ++j)
            {
                if(this->sudoku[i][j] == 0)
                    return false;
            }
        }
        return true;
    }

    void sudokuDFS(int i, int j)
    {
        if(j >= 9)
        {
            j-=9;
            i++;
        }
        if(i >= 9)
            return;

        if(this->sudoku[i][j] != 0)
        {
            sudokuDFS(i, j + 1);
        }
        else{
            for(int num = 1; num <= 9; ++num)
            {
                if(sudokuCheck(i, j, num))
                {
                    this->sudoku[i][j] = num;
                    sudokuDFS(i, j + 1);
                    if(sudokuCkeckDFS())
                        return;
                    this->sudoku[i][j] = 0;
                }
            }
        }
    }

    void sudokuPrint()
    {
        for(int i = 0; i < 9; ++i)
        {
            for(int j = 0; j < 9; ++j)
                cout<<sudoku[i][j] <<" ";
            cout << endl;
        }
    }
};

int main()
{
    Sudoku sudoku;
    sudoku.sudokuDFS(0, 0);
    sudoku.sudokuPrint();
    return 0;
}


发表于 2021-09-01 10:05:27 回复(0)
最典型的深度优先搜索题,刷题还是力扣好用😥
import java.util.Scanner;

public class Main {
    
    static boolean[][] rowBit = new boolean[9][9];
    static boolean[][] colBit = new boolean[9][9];
    static boolean[][] boxBit = new boolean[9][9];
    
    public static void main(String args[]) {
        int[][] question = new int[9][9];
        Scanner scan = new Scanner(System.in);
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                int t = scan.nextInt();
                question[row][col] = t;
                if (t == 0)
                    continue;
                setBit(row, col, t, true);
            }
        }
        if (!solveSudoku(question, 0, 0))
            System.out.println("无解");
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                System.out.print(question[row][col]+" ");
            }
            System.out.println();
        }
        
    }
    
    public static boolean solveSudoku(int[][] q, int i, int j) {
        for (; i < 9; i++) {
            for (j = 0;j < 9; j++) {
                // 找到空位
                if (q[i][j] == 0) {
                    // 找一个可以填的数填入,递归
                    for (int test = 1; test < 10; test++) {
                        if (!rowBit[i][test-1] && !colBit[j][test-1] && !boxBit[getBox(i, j)][test-1]) {
                            q[i][j] = test;
                            setBit(i, j, test, true);
                            if (solveSudoku(q, i, j))
                                return true;
                            q[i][j] = 0;
                            setBit(i, j, test, false);
                        }
                        // 没有任何数可以填入
                        if (test == 9)
                            return false;
                    }
                }
            }
        }
        return true;
    }
    
    public static int getBox(int row, int col) {
        return (row / 3) * 3 + col / 3;
    }
    
    public static void setBit(int i, int j, int test, boolean f) {
        rowBit[i][test-1] = f;
        colBit[j][test-1] = f;
        boxBit[getBox(i, j)][test-1] = f;
    }
}


发表于 2021-08-19 00:06:29 回复(0)
// 回溯,验证数的合法性的地方想了一下(
// 思路大概就是如下
#include <iostream>
#include <vector>

using namespace std;

bool isValid(vector<vector<int>>& arr, int i, int j, int num) {
    for (int k = 0; k < 9; k++) {
        if (arr[k][j] == num)  // 列中重复
            return false;
        if (arr[i][k] == num)  // 行中重复
            return false;
        if (arr[(i / 3) * 3 + k / 3][(j / 3) * 3 + k % 3] ==
                num) //3*3方格内是否有重复
            return false;
    }
    return true;
}

// 返回bool值,一找到可行解就return,省时间
bool backtrack(vector<vector<int>>& arr, int i, int j) {
    if (i == 9)    // base case,碰到直接返回
        return true;
    if (j == 9) // 这一行穷举完了就换下一行
        return backtrack(arr, i + 1, 0);
    if (arr[i][j] != 0) // 这格已经有数字了的话就跳过
        return backtrack(arr, i, j + 1);
    // 对每个格子,可以选择1~9
    for (int k = 1; k <= 9; k++) {
        // 先判断当前的数字能否放到格子里, 剪枝
        if (!isValid(arr, i, j, k))
            continue;
        // 做选择
        arr[i][j] = k;
        // 继续穷举右边一个
        if (backtrack(arr, i, j + 1))
            return true;
        //撤销选择
        arr[i][j] = 0;
    }
    return false;
}

int main() {
    vector<vector<int>> arr(9, vector(9, 0));
    for (int i = 0; i < 9; i++)
        for (int j = 0; j < 9; j++)
            cin >> arr[i][j];
    backtrack(arr, 0, 0);
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++)
            cout << arr[i][j] << " ";
        cout << endl;
    }
}

发表于 2023-04-16 20:16:59 回复(0)
3*3是可以的,但一个用列不过
import java.util.*;
public class Main {
        public static void main(String[] args) {
            Scanner in = new Scanner(System.in);
            int[][] map=new int[9][9];
            for(int i=0;i<9;i++){
                for(int j=0;j<9;j++){
                    map[i][j]=in.nextInt();
                }
            }
            for(int i=0;i<9;i++){
                for(int j=0;j<9;j++){
                    if(map[i][j]==0){
                        int s[]=new int[10];
                        int x=i/3;
                        int y=j/3;
                        for(int k=x*3;k<x*3+3;k++){
                            for(int z=y*3;z<y*3+3;z++){
                                s[map[k][z]]=map[k][z];
                            }
                        }
                        for(int k1=1;k1<10;k1++){
                            if(s[k1]==0)map[i][j]=k1;
                        }
                    }
                }
            }
            for(int i=0;i<9;i++){
                for(int j=0;j<9;j++){
                    System.out.print(map[i][j]+" ");
                }
                System.out.println();
            }
        }
}
发表于 2022-04-12 16:04:33 回复(0)
小白落泪,别人写的难看懂。自己吭吭哧哧写写,再debug下。终于给出的用例和自己改的用例都通过了。提交显示超时。。。。
时间就这么流走了!!!!
发表于 2021-01-26 18:06:12 回复(2)
#include <iostream>

using namespace std;
int flag = 0;
int a[9][9];
//思想
//遍历矩阵,判断数字是否为0
//若为0,判断1-9哪个数字合适(因此需要判断,0所在行,所在列,所在9宫格是否有重复)
//若没有重复,则复制,继续循环到第81个数字,那么说明数独填数成功
bool isok(int n,int k)
{
    int x = n/9;
    int y = n%9;
    for(int i=0;i<9;i++)
    {
        if(a[x][i] == k)    return false;
    }
    
    for(int i=0;i<9;i++)
    {
        if(a[i][y] == k)    return false;
    }
    
    x = x/3 *3;
    y = y/3 *3;
    for(int i = x;i<x+3;i++)
    {
        for(int j = y;j<y+3;j++)
        {
            if(a[i][y] == k)    return false;
        }
    }
    return true;
}

void dfs(int n)
{
    if(n > 80)
    {
        flag =1;
        return ;
    }
    int x = n/9;
    int y = n%9;
    if(a[x][y] != 0)
    {
        dfs(n+1);
    }
    else
    {
        for(int i = 1;i<=9;i++)
        {
            if(isok(n,i))
            {
                a[x][y] = i;
                dfs(n+1);
                if(flag == 1)
                    return;
                else
                    a[x][y] = 0;
            }
        }
    }
    
}
int main()
{
    for(int i = 0;i<9;i++)
        for(int j = 0;j<9;j++)
            cin>>a[i][j];
    dfs(0);
    
    for(int i = 0;i<9;i++)
    {
        for(int j = 0;j<9;j++)
        {
            cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

发表于 2020-07-20 15:05:15 回复(0)

问题信息

难度:
173条回答 27249浏览

热门推荐

通过挑战的用户

查看代码