Go语言实现
package main
import (
"fmt"
"os"
)
const (
N = 9
EmptyCell = '0'
)
func main() {
if len(os.Args) != 2 || len(os.Args[1]) != 81 {
fmt.Println("错误:程序需要一个正好包含 81 位数字的参数。")
os.Exit(1)
}
board := parseBoard(os.Args[1])
fmt.Println("未解决的数独:")
printGrid(board)
if solveSudoku(&board) {
fmt.Println("已解决数独:")
printGrid(board)
} else {
fmt.Println("没有解决方案")
}
}
// parseBoard
// 将字符串转换为 81 位数字的二维数组
func parseBoard(input string) [N][N]rune {
var board [N][N]rune
for i, char := range input {
board[i/N][i%N] = char
}
return board
}
// solveSudoku
// 采用部分填充的网格,并尝试将值分配给所有未分配的位置,以满足数独解决方案的要求
func solveSudoku(grid *[N][N]rune) bool {
row, col := findEmptyCell(grid)
if row == -1 {
return true
}
for num := '1'; num <= '9'; num++ {
if isSafe(grid, row, col, num) {
grid[row][col] = num
if solveSudoku(grid) {
return true
}
grid[row][col] = EmptyCell // 回溯
}
}
return false
}
// findEmptyCell
// 返回未填充的单元格的行和列
func findEmptyCell(board *[N][N]rune) (int, int) {
for i := 0; i < N; i++ {
for j := 0; j < N; j++ {
if board[i][j] == EmptyCell {
return i, j
}
}
}
return -1, -1
}
// isSafe
// 检查将 num 分配给给定的行是否合法
func isSafe(board *[N][N]rune, row, col int, num rune) bool {
// 检查此行
for x := 0; x < N; x++ {
if board[row][x] == num {
return false
}
}
// 检查此列
for y := 0; y < N; y++ {
if board[y][col] == num {
return false
}
}
// 选中此框
startRow := row - row%3
startCol := col - col%3
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if board[i+startRow][j+startCol] == num {
return false
}
}
}
return true
}
// printGrid
// 打印网格
func printGrid(board [N][N]rune) {
for i := 0; i < N; i++ {
for j := 0; j < N; j++ {
fmt.Printf("%c ", board[i][j])
}
fmt.Println()
}
}
C语言实现
#include <stdio.h>
#include <string.h>
#include <locale.h>
#define UNASSIGNED 0
#define N 9
// 检查将 num 分配给给定行是否合法的函数
int isSafe(int grid[N][N], int row, int col, int num);
// 打印网格
void printGrid(int grid[N][N]) {
for (int row = 0; row < N; row++) {
for (int col = 0; col < N; col++)
printf("%2d", grid[row][col]);
printf("\n");
}
}
// 此函数在网格中查找仍未分配的条目
int findUnassignedLocation(int grid[N][N], int *row, int *col) {
for (*row = 0; *row < N; (*row)++)
for (*col = 0; *col < N; (*col)++)
if (grid[*row][*col] == UNASSIGNED)
return 1;
return 0;
}
// 检查将 num 分配给给定的行是否合法
int isSafe(int grid[N][N], int row, int col, int num) {
// 检查“num”是否尚未放置在当前行、当前列和当前 3x3 框中
int boxStartRow = row - row % 3;
int boxStartCol = col - col % 3;
for (int i = 0; i < N; i++)
if (grid[row][i] == num || grid[i][col] == num || grid[boxStartRow + i / 3][boxStartCol + i % 3] == num)
return 0;
return 1;
}
// 采用部分填充的网格,并尝试将值分配给所有未分配的位置,以满足数独解决方案的要求
int solveSudoku(int grid[N][N]) {
int row, col;
// 如果没有未分配的位置,我们就完成了
if (!findUnassignedLocation(grid, &row, &col))
return 1; // 成功!
// 数字 1 到 9
for (int num = 1; num <= N; num++) {
// 如果合法
if (isSafe(grid, row, col, num)) {
// 进行暂定分配
grid[row][col] = num;
// 如果成功,则返回
if (solveSudoku(grid))
return 1;
// 失败,取消并重试
grid[row][col] = UNASSIGNED;
}
}
return 0; // 触发回溯
}
int main(int argc, char *argv[]) {
// 设置C库函数使用的locale
setlocale(LC_ALL, "");
int grid[N][N];
// 检查是否提供了正确数量的参数
if (argc != 2 || strlen(argv[1]) != N*N) {
wprintf(L"错误:程序需要一个正好包含 81 位数字的参数。\n");
return 1;
}
// 将输入字符解析为网格
for (int i = 0; i < N*N; i++) {
if (argv[1][i] >= '0' && argv[1][i] <= '9') {
grid[i/N][i%N] = argv[1][i] - '0';
} else {
wprintf(L"错误:参数应仅包含数字。\n");
return 1;
}
}
// 在求解之前打印网格
wprintf(L"未解决的数独:\n");
printGrid(grid);
// 如果成功,打印已解决的数独题
if (solveSudoku(grid) == 1) {
wprintf(L"已解决数独:\n");
printGrid(grid);
} else {
wprintf(L"对于提供的数独,没有解决方案。\n");
}
return 0;
}
使用方法如下:
Sudoku.exe 090020051010050603050000400530900000020001005600075108100400067300010020000087000