首页 > 代码库 > LA 2659 && poj 3076 && zoj 3122 Sudoku(精确覆盖 + DLX)
LA 2659 && poj 3076 && zoj 3122 Sudoku(精确覆盖 + DLX)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=660
TimeLimit: 3.000 seconds
A Sudoku grid is a 16 x 16 grid of cells grouped in sixteen 4 x 4 squares, where some cells are filled with letters from A to P (the first 16 capital letters of the English alphabet), as shown in figure 1a. The game is to fill all the empty grid cells with letters from A to P such that each letter from the grid occurs once only in the line, the column, and the 4 x 4 square it occupies. The initial content of the grid satisfies the constraints mentioned above and guarantees a unique solution.
A | C | O | I | ||||||||||||
J | A | B | P | C | G | F | H | ||||||||
D | F | I | E | P | |||||||||||
G | E | L | H | M | J | ||||||||||
E | C | G | |||||||||||||
I | K | G | A | B | E | J | |||||||||
D | G | P | J | F | A | ||||||||||
E | C | B | D | P | O | ||||||||||
E | F | M | D | L | K | A | |||||||||
C | O | I | L | ||||||||||||
H | P | C | F | A | B | ||||||||||
G | O | D | J | H | |||||||||||
K | J | H | A | P | L | ||||||||||
B | P | E | K | A | |||||||||||
H | B | K | F | I | C | ||||||||||
F | C | D | H | N | |||||||||||
F | P | A | H | M | J | E | C | N | L | B | D | K | O | G | I |
O | J | M | I | A | N | B | D | P | K | C | G | F | L | H | E |
L | N | D | K | G | F | O | I | J | E | A | H | M | B | P | C |
B | G | C | E | L | K | H | P | O | F | I | M | A | J | D | N |
M | F | H | B | E | L | P | O | A | C | K | J | G | N | I | D |
C | I | L | N | K | D | G | A | H | B | M | O | P | E | F | J |
D | O | G | P | I | H | J | M | F | N | L | E | C | A | K | B |
J | E | K | A | F | C | N | B | G | I | D | P | L | H | O | M |
E | B | O | F | P | M | I | J | D | G | H | L | N | K | C | A |
N | C | J | D | H | B | A | E | K | M | O | F | I | G | L | P |
H | M | P | L | C | G | K | F | I | A | E | N | B | D | J | O |
A | K | I | G | N | O | D | L | B | P | J | C | E | F | M | H |
K | D | E | M | J | I | F | N | C | H | G | A | O | P | B | L |
G | L | B | C | D | P | M | H | E | O | N | K | J | I | A | F |
P | H | N | O | B | A | L | K | M | J | F | I | D | C | E | G |
I | A | F | J | O | E | C | G | L | D | P | B | H | M | N | K |
Write a Sudoku playing program that reads data sets from a text file.
Input
Each data set encodes a grid and contains 16 strings on 16 consecutive lines as shown in figure 2. The i-th string stands for the i-th line of the grid, is 16 characters long, and starts from the first position of the line. String characters are from the set {A,B,...,P,-}, where `-‘ (minus) designates empty grid cells. The data sets are separated by single empty lines and terminate with an end of file.
Output
The program prints the solution of the input encoded grids in the same format and order as used for input.
Sample Input
--A----C-----O-I -J--A-B-P-CGF-H- --D--F-I-E----P- -G-EL-H----M-J-- ----E----C--G--- -I--K-GA-B---E-J D-GP--J-F----A-- -E---C-B--DP--O- E--F-M--D--L-K-A -C--------O-I-L- H-P-C--F-A--B--- ---G-OD---J----H K---J----H-A-P-L --B--P--E--K--A- -H--B--K--FI-C-- --F---C--D--H-N-
Sample Output
FPAHMJECNLBDKOGI OJMIANBDPKCGFLHE LNDKGFOIJEAHMBPC BGCELKHPOFIMAJDN MFHBELPOACKJGNID CILNKDGAHBMOPEFJ DOGPIHJMFNLECAKB JEKAFCNBGIDPLHOM EBOFPMIJDGHLNKCA NCJDHBAEKMOFIGLP HMPLCGKFIAENBDJO AKIGNODLBPJCEFMH KDEMJIFNCHGAOPBL GLBCDPMHEONKJIAF PHNOBALKMJFIDCEG IAFJOECGLDPBHMNK
1.每行A~P恰好各出现一次
2.每列A~P恰好各出现一次
3.粗线分隔出的每个4*4子方阵(一共有4*4个)中,A~P恰好各出现一次。
分析:直接套DLX
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int maxn = 1024 + 10; const int maxr = 4096 + 10; const int maxnode = maxr * 4 + maxn; // 行编号从1开始,列编号为1~n,结点0是表头结点,节点1~n是各列顶部的虚拟结点 struct DLX { int n, sz; // 列数,结点总数 int S[maxn]; // 各列结点数 int row[maxnode], col[maxnode]; // 各结点行列编号 int L[maxnode], R[maxnode], U[maxnode], D[maxnode]; // 十字链表 int ansd, ans[maxr]; // 解 void init(int n) { // n是列数 this->n = n; // 虚拟结点 for(int i = 0; i <= n; i++) { U[i] = i; D[i] = i; L[i] = i - 1; R[i] = i + 1; } R[n] = 0; L[0] = n; sz = n + 1; memset(S, 0, sizeof(S)); } void addRow(int r, vector<int> columns) { int first = sz; for(int i = 0; i < columns.size(); i++) { int c = columns[i]; L[sz] = sz - 1; R[sz] = sz + 1; D[sz] = c; U[sz] = U[c]; D[U[c]] = sz; U[c] = sz; row[sz] = r; col[sz] = c; S[c]++; sz++; } R[sz-1] = first; L[first] = sz - 1; } // 顺着链表,遍历除s外的其他元素 #define FOR(i, A, s) for(int i = A[s]; i != s; i = A[i]) void remove(int c) { L[R[c]] = L[c]; R[L[c]] = R[c]; for(int i = D[c]; i != c; i = D[i]) for(int j = R[i]; j != i; j = R[j]) { U[D[j]] = U[j]; D[U[j]] = D[j]; --S[col[j]]; } } void restore(int c) { for(int i = U[c]; i != c; i = U[i]) for(int j = L[i]; j != i; j = L[j]) { ++S[col[j]]; U[D[j]] = j; D[U[j]] = j; } L[R[c]] = c; R[L[c]] = c; } // d为递归深度 bool dfs(int d) { if(R[0] == 0) { // 找到解 ansd = d; // 记录解的长度 return true; } int c = R[0]; //第一个未删除的列 for(int i = R[0]; i != 0; i = R[i]) if(S[i] < S[c]) c = i; remove(c); // 删除第c列 for(int i = D[c]; i != c; i = D[i]) { // 用结点i所在行覆盖第c列 ans[d] = row[i]; for(int j = R[i]; j != i; j = R[j]) remove(col[j]); // 删除结点i所在行能覆盖的所有其他列 if(dfs(d + 1)) return true; for(int j = L[i]; j != i; j = L[j]) restore(col[j]); // 恢复结点i所在行能覆盖的所有其他列 } restore(c); // 恢复第c列 return false; } bool solve(vector<int> &v) { v.clear(); if(!dfs(0)) return false; for(int i = 0; i < ansd; i++) v.push_back(ans[i]); return true; } }; DLX solver; const int SLOT = 0; const int ROW = 1; const int COL = 2; const int SUB = 3; // 行/列的统一编解码函数,从1开始编号 inline int encode(int a, int b, int c) { return a * 256 + b * 16 + c + 1; } void decode(int code, int &a, int &b, int &c) { code--; c = code % 16; code /= 16; b = code % 16; code /= 16; a = code; } char puzzle[16][20]; bool read() { for(int i = 0; i < 16; i++) if(scanf("%s", puzzle[i]) == EOF) return false; return true; } int main() { int kase = 0; while(read()) { if(++kase != 1) printf("\n"); solver.init(1024); for(int r = 0; r < 16; r++) for(int c = 0; c < 16; c++) for(int v = 0; v < 16; v++) if(puzzle[r][c] == '-' || puzzle[r][c] == 'A' + v) { vector<int> columns; columns.push_back(encode(SLOT, r, c)); columns.push_back(encode(ROW, r, v)); columns.push_back(encode(COL, c, v)); columns.push_back(encode(SUB, (r/4)*4+c/4, v)); solver.addRow(encode(r, c, v), columns); } vector<int> ans; solver.solve(ans); for(int i = 0; i < ans.size(); i++) { int r, c, v; decode(ans[i], r, c, v); puzzle[r][c] = 'A' + v; } for(int i = 0; i < 16; i++) printf("%s\n", puzzle[i]); } return 0; }
LA 2659 && poj 3076 && zoj 3122 Sudoku(精确覆盖 + DLX)