Squiggly Sudoku
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 691 Accepted Submission(s): 291
Left figure is the puzzle and right figure is one solution.
Now, give you the information of the puzzle, please tell me is there no solution or multiple solution or one solution.
Each case contains nine lines, Each line contains nine integers.
Each module number tells the information of the gird and is the sum of up to five integers:
0~9: '0' means this gird is empty, '1' - '9' means the gird is already filled in.
16: wall to the up
32: wall to the right
64: wall to the down
128: wall to the left
I promise there must be nine Connecting-sub-grids, and each contains nine girds.
數獨,與普通數獨不同的是把傳統的數獨的 3*3 的九宮換成了 9 格相連的奇怪圖形;同樣要求在這 9 個格子裏數字不重複,行不重複,列不重複。
給不同的九個奇怪圖形標號 0 到 8 就行了。然後用搜索,一直 TLE,用了各種加速手段。。。
後來用了DLX,一開始還是 TLE,最後犧牲了一下代碼的優雅度,把一個 return 提到循環內,終於 AC 了,我了個去,數據真 BT。
好吧,做過這一題之後也算有所收穫吧。
有了 DLX 模板了,雖然是連偷帶抄,但也是自己一行一行打,調試出來的;
也看了 Knuth 的 Algoritm X,明白了有一些問題可以轉化成 Extra Cover Problem 用 Algorithm X 來解決,這時就可以讓 DLX 發揮威力啦。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
using namespace std;
#define ROWS_MAX (9*9*9 + 1)
#define COLS_MAX (9*9*4 + 1)
#define NODES_MAX (ROWS_MAX * COLS_MAX + COLS_MAX + 1)
#define ON_BACKTRACKED() \
do {if (slns >= 2) return;} while (0)
struct DLX {
/*
* 'U', 'D', 'L', 'R', 'S' are notations from Knuth's paper.
* 'col' access a node's column number;
* 'row' access a node's row number.
*/
int U [NODES_MAX];
int D [NODES_MAX];
int L [NODES_MAX];
int R [NODES_MAX];
int S [NODES_MAX];
int col [NODES_MAX];
int row [NODES_MAX];
int nodes;
int rows, cols;
int sln [ROWS_MAX]; // solution for 'Extra Cover Problem'
int tryingSln [ROWS_MAX]; // the trying solution
int slns; // number of solutions
int slnElems; // number of elements in the saved solution 'sln'
#ifdef _DEBUG
int treeSize;
#endif
int AddNode (int up, int down, int left, int right) {
U [nodes] = up;
D [nodes] = down;
L [nodes] = left;
R [nodes] = right;
D [up] = U [down] = L [right] = R [left] = nodes;
return nodes++;
}
void Init (int (*mat)[COLS_MAX], int rs, int cs) {
rows = rs;
cols = cs;
nodes = 0;
AddNode (0, 0, 0, 0);
for (int i=1; i<=cols; ++i) {
row[i] = 0;
col[i] = i;
AddNode (i, i, L[0], 0);
}
memset (S, 0, sizeof (S));
for (int i=1; i<=rows; ++i) {
int added = -1;
for (int k=1; k<=cols; ++k) {
if (! mat [i][k]) {
continue;
}
if (added == -1) {
added = AddNode (U[k], k, nodes, nodes);
} else {
added = AddNode (U[k], k, added, R[added]);
}
++S[k];
row[added] = i;
col[added] = k;
}
}
}
void Cover (int c) {
L[R[c]] = L[c];
R[L[c]] = R[c];
for (int r=D[c]; r!=c; r=D[r]) {
for (int x=R[r]; x!=r; x=R[x]) {
--S[col[x]];
U[D[x]] = U[x];
D[U[x]] = D[x];
}
}
}
void Uncover (int c) {
for (int r=U[c]; r!=c; r=U[r]) {
for (int x=L[r]; x!=r; x=L[x]) {
++S[col[x]];
D[U[x]] = x;
U[D[x]] = x;
}
}
R[L[c]] = c;
L[R[c]] = c;
}
#ifdef _DEBUG
void PrintCol (int c) {
printf ("col %d:\n", c);
for (int i=D[c]; i!=c; i=D[i]) {
printf ("=>(%d [%d] %d)<=", L[i], i, R[i]);
}
printf ("\n");
}
void Print () {
for (int i=1; i<=cols; ++i) {
PrintCol (i);
}
}
#endif
void AlgorithmX (int depth) {
#ifdef _DEBUG
//Print();
++treeSize;
#endif
if (R[0] == 0) {
// return succefully
++slns;
slnElems = depth;
memcpy (sln, tryingSln, sizeof (sln));
return;
}
int minSCol = R[0];
for (int c=R[0]; c!=0; c=R[c]) {
if (S[c] < S[minSCol]) {
minSCol = c;
}
}
if (S[minSCol] == 0) {
// return failed
return;
}
Cover (minSCol);
for (int r=D[minSCol]; r!=minSCol; r=D[r]) {
for (int c=R[r]; c!=r; c=R[c]) {
Cover (col[c]);
}
tryingSln[depth] = row[r];
AlgorithmX (depth + 1);
ON_BACKTRACKED();
for (int c=L[r]; c!=r; c=L[c]) {
Uncover (col[c]);
}
}
Uncover (minSCol);
}
};
#define UWALL(x) ((x) & 16)
#define RWALL(x) ((x) & 32)
#define DWALL(x) ((x) & 64)
#define LWALL(x) ((x) & 128)
#define NO(x) ((x) & ~16 & ~32 & ~64 & ~128)
int sudoku[9][9];
int block[9][9];
DLX dlx;
void FloodFill (int row, int col, int no) {
assert (0 <= row && row < 9);
assert (0 <= col && col < 9);
if (block[row][col] != -1) {
return;
}
block[row][col] = no;
if (! UWALL(sudoku[row][col])) {
FloodFill (row - 1, col, no);
}
if (! RWALL(sudoku[row][col])) {
FloodFill (row, col + 1, no);
}
if (! DWALL(sudoku[row][col])) {
FloodFill (row + 1, col, no);
}
if (! LWALL(sudoku[row][col])) {
FloodFill (row, col - 1, no);
}
}
#ifdef _DEBUG
void PrintSudoku () {
printf ("\n");
for (int i=0; i<9; ++i) {
for (int k=0; k<9; ++k) {
printf ("%s", UWALL(sudoku[i][k]) ? "+---" : " ");
}
printf ("\n");
for (int k=0; k<9; ++k) {
printf ("%s %d ", LWALL(sudoku[i][k]) ? "|" : " ", NO(sudoku[i][k]));
}
printf ("\n");
}
printf ("\n");
}
void PrintBlock () {
printf ("\n");
for (int i=0; i<9; ++i) {
for (int k=0; k<9; ++k) {
printf ("%2d%s", block[i][k], k==8 ? "\n" : "");
}
}
printf ("\n");
}
#endif
void Solve () {
for (int i=0; i<9; ++i) {
for (int k=0; k<9; ++k) {
if (scanf ("%d", &sudoku[i][k]) == EOF) {
return;
}
}
}
// devide the chess board into 9 blocks, numbered 0, 1, ..., 8.
memset (block, -1, sizeof (block));
int b = 0;
for (int i=0; i<9; ++i) {
for (int k=0; k<9; ++k) {
if (block[i][k] == -1) {
FloodFill (i, k, b++);
}
}
}
assert (b == 9);
#ifdef _DEBUG
//PrintSudoku();
//PrintBlock();
#endif
// the following procedure checks whether the sudoku is solvable.
bool isCovered[4 * 9 * 9 + 1];
memset (isCovered, 0, sizeof (isCovered));
bool isSolvable = true;
for (int i=0; i<9 && isSolvable; ++i) {
for (int k=0; k<9 && isSolvable; ++k) {
int no = NO(sudoku[i][k]);
if (! no) {
continue;
}
isCovered[i * 9 + k + 1] = true;
if (isCovered[81 + block[i][k] * 9 + no]) {
isSolvable = false;
} else {
isCovered[81 + block[i][k] * 9 + no] = true;
}
if (isCovered[81 * 2 + i * 9 + no]) {
isSolvable = false;
} else {
isCovered[81 * 2 + i * 9 + no] = true;
}
if (isCovered[81 * 3 + k * 9 + no]) {
isSolvable = false;
} else {
isCovered[81 * 3 + k * 9 + no] = true;
}
}
}
static int cs = 0;
if (! isSolvable) {
printf ("Case %d:\nNo solution\n", ++cs);
return;
}
/*
* the following procedure transform the sudoku into a 'Extra Cover Problem'
* so that we can run the 'Algorithm X' and take advantage of 'DLX'.
*/
int mat[9 * 9 * 9 + 1][4 * 9 * 9 + 1];
memset (mat, 0, sizeof (mat));
for (int i=0; i<9; ++i) {
for (int k=0; k<9; ++k) {
for (int n=0; n<9; ++n) {
mat[i*81 + k*9 + n + 1][i*9 + k + 1] = 1;
mat[i*81 + k*9 + n + 1][81 + block[i][k]*9 + n + 1] = 1;
mat[i*81 + k*9 + n + 1][81*2 + i*9 + n + 1] = 1;
mat[i*81 + k*9 + n + 1][81*3 + k*9 + n + 1] = 1;
}
}
}
dlx.Init (mat, 9 * 9 * 9, 4 * 9 * 9);
for (int i=1; i<=4*9*9; ++i) {
if (isCovered[i]) {
dlx.Cover (i);
}
}
#ifdef _DEBUG
dlx.treeSize = 0;
#endif
dlx.slns = 0;
dlx.AlgorithmX (0);
#ifdef _DEBUG
printf ("tree size = %d\n", dlx.treeSize);
#endif
if (dlx.slns <= 0) {
printf ("Case %d:\nNo solution\n", ++cs);
return;
}
if (dlx.slns >= 2) {
printf ("Case %d:\nMultiple Solutions\n", ++cs);
return;
}
printf ("Case %d:\n", ++cs);
for (int i=0; i<dlx.slnElems; ++i) {
int n = dlx.sln[i] - 1;
int r = n / 81;
int c = n / 9 % 9;
n = n % 9 + 1;
assert (! NO(sudoku[r][c]));
sudoku[r][c] |= n;
}
for (int i=0; i<9; ++i) {
for (int k=0; k<9; ++k) {
assert (NO(sudoku[i][k]));
printf ("%d%s", NO(sudoku[i][k]), k==8 ? "\n" : "");
}
}
}
int main () {
int cs;
scanf ("%d", &cs);
while (cs--) {
Solve();
}
return 0;
}