题目地址
题意:给你一个数独残图,问你是不是能求出完整的图,完整的数独是什么样子的(唯一)。
思路:数独的限制条件就是4个,分别是
- 位置限制:每一格有且仅有一个数
- 列限制:每一列中每个数仅出现一次
- 行限制:每一行中每个数仅出现一次
- 区域限制:每个区域每个数仅出现一次
所以我们创建的矩阵要满足这些条件,所以我们划分出行的区间来表示这些限制条件
- 1-81行表示的是位置限制
- 82-162行表示的是列限制
- 163-243行表示的是行限制
- 244-324行表示的是区域限制
然后每一列表示的是该位置数的情况,比如mat[i][j]=2的话,那么(i*9+j)*9+2列的某些行(对应限制行)就为1,当如果是不确定的话(为没有填写的),那么就是把可以填的数字全部的列的某些行的值为1就好了,然后求一遍DLX的精确覆盖。
推荐知乎上一篇讲数独求解该怎样转化为精确覆盖问题:传送门
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <iomanip>
#define N 110
#define MAXSIZE 1010*1010
#define LL __int64
#define inf 0x3f3f3f3f
#define lson l,mid,ans<<1
#define rson mid+1,r,ans<<1|1
#define getMid (l+r)>>1
#define movel ans<<1
#define mover ans<<1|1
using namespace std;
const LL mod = 1000000007;
struct node {
int left, right, up, down, col, row;
}mapp[MAXSIZE];
int S[MAXSIZE], H[MAXSIZE];//S记录该列中1元素的个数
int head, cnt;
int ans[N];
int len;
struct Dancing_Links_X {
void init(int m) {
head = 0;
for (int i = 0; i <= m; i++) {
S[i] = 0;
mapp[i].up = mapp[i].down = i;
mapp[i].left = (i == 0 ? m : i - 1);
mapp[i].right = (i == m ? 0 : i + 1);
}
cnt = m;
memset(H, -1, sizeof(H));
}
void link(int x, int y) {
cnt++;
mapp[cnt].row = x;
mapp[cnt].col = y;
S[y]++;
mapp[cnt].up = mapp[y].up;
mapp[cnt].down = y;
mapp[mapp[y].up].down = cnt;
mapp[y].up = cnt;
if (H[x] == -1) H[x] = mapp[cnt].left = mapp[cnt].right = cnt;
else {
mapp[cnt].left = mapp[H[x]].left;
mapp[cnt].right = H[x];
mapp[mapp[H[x]].left].right = cnt;
mapp[H[x]].left = cnt;
}
}
void remove(int c) {//删去c这个点,以及关联的一列
mapp[mapp[c].right].left = mapp[c].left;
mapp[mapp[c].left].right = mapp[c].right;
for (int i = mapp[c].down; i != c; i = mapp[i].down) {
for (int j = mapp[i].right; j != i; j = mapp[j].right) {
mapp[mapp[j].down].up = mapp[j].up; mapp[mapp[j].up].down = mapp[j].down;
--S[mapp[j].col];
}
}
}
void resume(int c) {//恢复c这个点,以及关联的一列
for (int i = mapp[c].up; i != c; i = mapp[i].up) {
for (int j = mapp[i].left; j != i; j = mapp[j].left) {
++S[mapp[j].col];
mapp[mapp[j].down].up = mapp[mapp[j].up].down = j;
}
}
mapp[mapp[c].right].left = mapp[mapp[c].left].right = c;
}
bool dance(int k) {
if (mapp[head].right == head) {
len = k;
//cout << endl << len << endl << endl;
return true;
}
int s = inf, c;
for (int t = mapp[head].right; t != head; t = mapp[t].right) {
if (S[t] < s) s = S[t], c = t;
}
remove(c);
for (int i = mapp[c].down; i != c; i = mapp[i].down) {
ans[k] = mapp[i].row;
for (int j = mapp[i].right; j != i; j = mapp[j].right) {
remove(mapp[j].col);
}
if (dance(k + 1)) {
return true;
}
for (int j = mapp[i].left; j != i; j = mapp[j].left) {
resume(mapp[j].col);
}
}
resume(c);
return false;
}
}DLX;
int main() {
cin.sync_with_stdio(false);
int n, m;
char mat[N][N];
int T;
cin >> T;
while (T--) {
n = 9 * 9 * 9;//行
m = 9 * 9 * 4;//列
DLX.init(m);
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
cin >> mat[i][j];
}
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (mat[i][j] != '0') {
int r = (i * 9 + j) * 9 + mat[i][j] - '0';
int c1 = i * 9 + j + 1;
int c2 = 81 + i * 9 + mat[i][j] - '0';
int c3 = 162 + j * 9 + mat[i][j] - '0';
int c4 = 243 + (i / 3 * 3 + j / 3) * 9 + mat[i][j] - '0';
DLX.link(r, c1);
DLX.link(r, c2);
DLX.link(r, c3);
DLX.link(r, c4);
S[c1] = S[c2] = S[c3] = S[c4] = -1;
}
}
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (mat[i][j] == '0') {
for (int k = 1; k <= 9; k++) {
int r = (i * 9 + j) * 9 + k;
int c1 = i * 9 + j + 1;
int c2 = 81 + i * 9 + k;
int c3 = 162 + j * 9 + k;
int c4 = 243 + (i / 3 * 3 + j / 3) * 9 + k;
if (~S[c1] && ~S[c2] && ~S[c3] && ~S[c4]) {
DLX.link(r, c1);
DLX.link(r, c2);
DLX.link(r, c3);
DLX.link(r, c4);
}
}
}
}
}
len = inf;
if (DLX.dance(0)) {
for (int i = 0; i < len; i++) {
int Orz = (ans[i] - 1) % 9 + 1;
int x = (ans[i] - 1) / 9 / 9;
int y = (ans[i] - 1) / 9 % 9;
mat[x][y] = Orz + '0';
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
cout << mat[i][j];
}
cout << endl;
}
}
else {
cout << "Could not complete this grid." << endl;
}
if (T) {
cout << endl;
}
}
return 0;
}