张德长

导航

牛客[编程题] HJ44 Sudoku数独游戏

HJ44 Sudoku
困难  通过率:27.56%  时间限制:1秒  空间限制:32M
 

描述

问题描述:数独(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

 

个人感觉,这个题目出的不好,有多种答案,但是题目只给出一种答案;只要不符合标准答案,即使满足要求,也无法通过;6个用例只通过了5个;

后面的Check函数不是为了解出答案,而是为了检查输出的结果;

本方法还有改进的空间,目前无法唯一确定某一个值时,都是从可能的选项中默认选择第一个;

其实如果默认第一个的情况下无法解出答案时,可以用Check+Random的方式,也就是每试一次都是从可能的选项中随机选择一个,如果不行就再来一遍;

前提时要先把能唯一确定的最终状态记录下来,后面开始通过无限循环一直进行查找,总能找到答案;

 using System;
    using System.Collections.Generic;
    public class Program
    {
        public static void Main()
        {
            string line; List<string> lines = new List<string>();
            while ((line = System.Console.ReadLine()) != null)
            { // 注意 while 处理多个 case
                lines.Add(line);

                if (lines.Count == 9)
                {
                    string[] lineArr;
                    int[,] arr = new int[9, 9];
                    int answer = 0; bool find;
                    for (int i = 0; i < 9; i++)
                    {
                        line = lines[i];
                        lineArr = line.Split(" ");
                        for (int j = 0; j < 9; j++)
                        {
                            arr[i, j] = int.Parse(lineArr[j]);
                        }
                    }
                    //最多循环81次
                    for (int k = 0; k < 81; k++)
                    {
                        if (k == 0)
                        {
                            find = true;
                        }
                        else
                        {
                            find = false;
                        }
                        for (int i = 0; i < 9; i++)
                        {
                            for (int j = 0; j < 9; j++)
                            {

                                if (arr[i, j] == 0)
                                {
                                    answer = GetAnswer(i, j, arr, find);
                                    if (answer != 0)
                                    {
                                        arr[i, j] = answer;
                                        find = true;
                                    }

                                }
                            }
                        }
                        //如果已完成,就立即结束循环
                        if (!HasZero(arr))
                        {
                            break;
                        }
                    }
                    
                    //输出
                    for (int i = 0; i < 9; i++)
                    {
                        line = string.Empty;
                        for (int j = 0; j < 9; j++)
                        {
                            line += arr[i, j].ToString();
                            if (j != 8)
                            {
                                line += " ";
                            }
                        }
                        Console.WriteLine(line);
                    }
                    Check(arr);
                }

            }
        }
        //获取某个空位的答案
        static int GetAnswer(int row, int column, int[,] arr, bool find)
        {
            //使用排除法确定可以填写的值
            //一共1-9九个,如果排除到只剩一个,那么就可以确定答案了
            List<int> left = new List<int>();
            for (int i = 1; i <= 9; i++)
            {
                left.Add(i);
            }
            //从行开始排除
            for (int i = 0; i < 9; i++)
            {
                if (i == column) continue;
                left.Remove(arr[row, i]);
            }
            if (left.Count == 1)
            {
                
                return left[0];
            }
            //再从列排除
            for (int i = 0; i < 9; i++)
            {
                if (i == row) continue;
                left.Remove(arr[i, column]);
            }
            if (left.Count == 1)
            {
                return left[0];
            }
            //从所在的九宫格排除
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    if (row / 3 * 3 + i == row && column / 3 * 3 + j == column)
                        continue;
                    left.Remove(arr[row / 3 * 3 + i, column / 3 * 3 + j]);
                }
            }
            if (left.Count == 1)
            {
                return left[0];
            }
            else if (!find && left.Count > 0)
            {
                return left[0];
            }
            return 0;
        }
        //判定矩阵中是否还有0,也就是判定是否已经完成
        static bool HasZero(int[,] arr)
        {
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (arr[i, j] == 0)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        static bool Check(int[,] arr)
        {
            if (HasZero(arr)) return false;
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    int answer = GetAnswer(i, j, arr, true);
                    if (answer != arr[i, j])
                    {
                        Console.WriteLine($"row={i},col={j},answer={answer},real={arr[i, j]}");
                        return false;
                    }
                }
            }
            return true;
        }
    }

 

posted on 2023-11-11 21:13  张德长  阅读(15)  评论(0编辑  收藏  举报