2021寒假每日一題《數獨檢查》
技術標籤:2021寒假每日一題java演算法模擬
數獨檢查
題目來源:Google Kickstart2013 Round B Problem A
時間限制:
1000
m
s
1000ms
1000ms 記憶體限制:
64
m
b
64mb
64mb
題目描述
數獨是一種流行的單人遊戲。
目標是用數字填充
9
∗
9
9*9
9∗9 矩陣,使每列,每行和所有
9
9
9 個非重疊的
3
∗
3
3*3
3∗3 子矩陣包含從
1
1
1 到
9
9
9 的所有數字。
每個
9
∗
9
9*9
9∗9 矩陣在遊戲開始時都會有部分數字已經給出,通常有一個獨特的解決方案。
給定完成的
N
2
∗
N
2
N^2 ∗ N^2
有效的解決方案必須滿足以下條件:
- 每行包含從 1 1 1 到 N 2 N^2 N2 的每個數字,每個數字一次。
- 每列包含從 1 1 1 到 N 2 N^2 N2 的每個數字,每個數字一次。
- 將 N 2 ∗ N 2 N^2 ∗ N^2 N2∗N2 矩陣劃分為 N 2 N^2 N2 個非重疊 N ∗ N N ∗ N N∗N 子矩陣。 每個子矩陣包含從 1 1 1 到 N 2 N^2 N2 的每個數字,每個數字一次。
你無需擔心問題答案的唯一性,只需檢查給定矩陣是否是有效的解決方案即可。
輸入格式
第一行包含整數
T
T
每組資料第一行包含整數
N
N
N 。
接下來
N
2
N^2
N2 行,每行包含
N
2
N^2
N2 個數字(均不超過1000),用來描述完整的數獨矩陣。
輸出格式
每組資料輸出一個結果,每個結果佔一行。
結果表示為“Case #x: y”,其中x是組別編號(從1開始),如果給定矩陣是有效方案則y是Yes,否則y是No。
資料範圍
1
≤
T
≤
100
1 ≤ T ≤ 100
1≤T≤100 ,
3
≤
N
≤
6
3 ≤ N ≤ 6
3≤N≤6
樣例輸入
3 3 5 3 4 6 7 8 9 1 2 6 7 2 1 9 5 3 4 8 1 9 8 3 4 2 5 6 7 8 5 9 7 6 1 4 2 3 4 2 6 8 5 3 7 9 1 7 1 3 9 2 4 8 5 6 9 6 1 5 3 7 2 8 4 2 8 7 4 1 9 6 3 5 3 4 5 2 8 6 1 7 9 3 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 3 5 3 4 6 7 8 9 1 2 6 7 2 1 9 5 3 4 8 1 9 8 3 4 2 5 6 7 8 5 9 7 6 1 4 2 3 4 2 6 8 999 3 7 9 1 7 1 3 9 2 4 8 5 6 9 6 1 5 3 7 2 8 4 2 8 7 4 1 9 6 3 5 3 4 5 2 8 6 1 7 9
樣例輸出
Case #1: Yes
Case #2: No
Case #3: No
解題思路
數獨的規則就是每一行、每一列、每一個、單元都由
[
1
,
n
2
]
[1,n^2]
[1,n2] 的陣列成,且不能重複。
只需要暴力檢查所有的情況就可以得到答案了。
第一步檢查: 檢查每一行,由於是第一個檢查,所以同時檢查資料規模是否在
[
1
,
n
2
]
[1,n^2]
[1,n2] 內。
用一個
H
a
s
h
S
e
t
HashSet
HashSet 來存一行中的元素,呼叫 HashSet.add()
將這一行的每個數數存入其中,如果數存在,就不會新增進去了。
新增完一行後,呼叫 HashSet.size()
判斷元素個數是否為
N
2
N^2
N2 個,如果不是,則返回 false
,如果是,則進行下一步檢查。
每行執行完後,記得呼叫 HashSet.clear()
將其清空。
第二步檢查: 檢查每列,方法同上。 H a s h S e t HashSet HashSet中存放的是每列的元素。
第三部檢查: 檢查每個
N
∗
N
N*N
N∗N 單元內的元素。
使用4層迴圈,將每個單元單獨列出,同樣使用
H
a
s
h
S
e
t
HashSet
HashSet存放元素。
for (int i = 0; i < m; i += n) {
for (int j = 0; j < m; j += n) {
for (int k = i; k < i + n; k++) {
for (int l = j; l < j + n; l++) {
hashset.add(sudoku[k][l]);
}
}
if (hashset.size() < m) {
return false;
}
hashset.clear();
}
}
如果全部檢查通過,則數獨成立,輸出 Case #%d: Yes
即可。
如果未通過則輸出 Case #%d: No
。
解題程式碼-Java
import java.util.Scanner;
import java.util.HashSet;
public class Main {
static boolean verifySudoku(int n, int[][] sudoku) {
int m = n * n;
//檢查每行是否符合要求,同時檢查資料規模是否符合要求
HashSet<Integer> hashset = new HashSet<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
if (sudoku[i][j] < 1 || sudoku[i][j] > m) {
return false;
}
hashset.add(sudoku[i][j]);
}
if (hashset.size() < m) {
return false;
}
hashset.clear();
}
//檢查每列是否符合要求
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
hashset.add(sudoku[j][i]);
}
if (hashset.size() < m) {
return false;
}
hashset.clear();
}
//檢查每個n*n格子內是否符合要求
for (int i = 0; i < m; i += n) {
for (int j = 0; j < m; j += n) {
for (int k = i; k < i + n; k++) {
for (int l = j; l < j + n; l++) {
hashset.add(sudoku[k][l]);
}
}
if (hashset.size() < m) {
return false;
}
hashset.clear();
}
}
return true;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int t = input.nextInt();
int count = 1;
while (count <= t) {
int n = input.nextInt();
int[][] sudoku = new int[n * n][n * n];
for (int i = 0; i < n * n; i++) {
for (int j = 0; j < n * n; j++) {
sudoku[i][j] = input.nextInt();
}
}
String flag = "No";
if (verifySudoku(n, sudoku)) {
flag = "Yes";
}
System.out.printf("Case #%d: %s", count, flag);
count++;
}
input.close();
}
}