#include
#include
#include
#include
#define DELPOINTER(p) if(nullptr!=(p)){delete[] (p),(p)=nullptr;}
#define DO(sth) for (DLXNode * pCol = pRow->right; pCol != pRow; pCol = pCol->right) {\
(sth)(pCol->elem.c);\
}
using namespace std;
int ans[1000];
unordered_map m;
struct ElemType {
int r, c;
ElemType(const int & _r = int(), const int & _c = int()) :r(_r), c(_c) {}
};
struct DLXNode {
ElemType elem;
DLXNode *up, *left, *down, *right;
DLXNode(const ElemType & _elem = ElemType(),
DLXNode * _up = nullptr, DLXNode * _left = nullptr, DLXNode * _down = nullptr, DLXNode * _right = nullptr)
:elem(_elem), up(_up), left(_left), down(_down), right(_right) {}
};
class DLX {
public:
DLX(const int & _row, const int & _col);
DLX(const vector > & mtx);
~DLX(void);
inline void addNode(const int & x, const int & y);
/* 双向链表的断开与连接操作 */
/* U L D R */
/* 上 左 下 右 */
inline void deleteUD(DLXNode * p);
inline void deleteLR(DLXNode * p);
inline void resumeUD(DLXNode * p);
inline void resumeLR(DLXNode * p);
void cover(const int & col);
void uncover(const int & col);
bool dance(const int & step);
inline DLXNode* getNode(const int & index);
private:
void init(const int & row, const int & col);
inline bool empty() { return m_pHead->left == m_pHead; }
inline int getMinColPos(); // 获取当前所有列中元素个数最小的一列
private:
int m_nIndex; // 有多少个节点
int m_nRowCount; // 行数
int m_nColCount; // 列数
int * m_pSz; // 每一列有多少个节点
DLXNode *m_pHead; // 头结点(入口)
DLXNode *m_pRows, *m_pCols; // 行指针与列指针
DLXNode *m_pNodes; // 所有的节点
};
DLX::DLX(const int & _row, const int & _col) {
init(_row, _col);
}
DLX::DLX(const vector > & mtx) {
/* 初始化 */
init(mtx.size(), mtx[0].size());
for (int i = m_nRowCount - 1; i >= 0; --i) {
for (int j = 0; j < m_nColCount; ++j) {
if (mtx[i][j]) {
addNode(i, j);
}
}
}
}
DLX::~DLX(void) {
DELPOINTER(m_pSz);
DELPOINTER(m_pHead);
DELPOINTER(m_pRows);
DELPOINTER(m_pCols);
DELPOINTER(m_pNodes);
}
inline void DLX::addNode(const int & x, const int & y) {
DLXNode * p = getNode(m_nIndex++);
p->elem = ElemType(x, y);
/* 前插 */
/* 向上的指针指向当前列的头指针 */
/* 向下的指针指向当前列的头指针的向下的指针 */
/* 也就是最后一次插入当前列的那个结点(Node')*/
/* 头指针的向下指针指向当前节点 */
/* Node' 的向上指针指向当前节点 */
/* 此时当前节点位于头结点和 Node' 之间 */
/* 头节点 <--> p <--> Node' */
p->up = &m_pCols[y];
p->down = m_pCols[y].down;
p->up->down = p->down->up = p;
// 后插(原理同上)
p->right = &m_pRows[x];
p->left = m_pRows[x].left;
p->left->right = p->right->left = p;
++m_pSz[y];
}
inline DLXNode* DLX::getNode(const int & index) {
return &m_pNodes[index];
}
inline void DLX::deleteUD(DLXNode * p) {
p->up->down = p->down;
p->down->up = p->up;
}
inline void DLX::deleteLR(DLXNode * p) {
p->left->right = p->right;
p->right->left = p->left;
}
inline void DLX::resumeUD(DLXNode * p) {
p->up->down = p->down->up = p;
}
inline void DLX::resumeLR(DLXNode * p) {
p->left->right = p->right->left = p;
}
void DLX::cover(const int & col) {
if (col == m_nColCount) {
return;
}
// 先删除当前列的头结点
deleteLR(&m_pCols[col]);
// 找到当前列的所有Node
for (DLXNode * pCol = m_pCols[col].down; pCol != &m_pCols[col]; pCol = pCol->down) {
if (pCol->elem.c == m_nColCount) {
continue;
}
// 找到这一行与当前Node相连的Node,然后删除这一行
for (DLXNode * pRow = pCol->left; pRow != pCol; pRow = pRow->left) {
if (pRow->elem.c == m_nColCount) {
continue;
}
--m_pSz[pRow->elem.c];
deleteUD(pRow);
}
deleteLR(pCol);
}
}
void DLX::uncover(const int & col) {
// 和cover是镜像操作
if (col == m_nColCount) {
return;
}
for (DLXNode * pCol = m_pCols[col].down; pCol != &m_pCols[col]; pCol = pCol->down) {
if (pCol->elem.c == m_nColCount) {
continue;
}
resumeLR(pCol);
for (DLXNode * pRow = pCol->left; pRow != pCol; pRow = pRow->left) {
if (pRow->elem.c == m_nColCount) {
continue;
}
++m_pSz[pRow->elem.c];
resumeUD(pRow);
}
}
resumeLR(&m_pCols[col]);
}
bool DLX::dance(const int & step) {
if (empty()) {
sort(ans, ans + step);
// 输出结果
for (int i = 0; i < step; ++i) {
if (0 == i % 9) {
cout << endl;
}
cout << m[ans[i] + 1] << ' ';
}
return true;
}
int col = getMinColPos();
/* 删掉这一列 */
cover(col);
for (DLXNode * pRow = m_pCols[col].down; pRow != &m_pCols[col]; pRow = pRow->down) {
/* 断开循环链表 */
pRow->left->right = pRow;
/* 删除这一列对应的(所有行的节点(所在的列)) */
DO(cover);
ans[step] = pRow->elem.r;
if (dance(step + 1)) {
return true;
}
/* 恢复这一列对应的(所有行的节点(所在的列)) */
DO(uncover);
/* 连接循环链表 */
pRow->left->right = pRow->right;
}
/* 恢复这一列 */
uncover(col);
return false;
}
void DLX::init(const int & row, const int & col) {
m_nRowCount = row;
m_nColCount = col;
m_nIndex = 0;
if (row <= 0 || col <= 0) {
m_pSz = nullptr;
m_pHead = m_pRows = m_pCols = m_pNodes = nullptr;
}
else {
m_pSz = new int[col];
m_pHead = new DLXNode;
m_pRows = new DLXNode[row];
m_pCols = new DLXNode[col];
m_pNodes = new DLXNode[row * col];
m_pHead->elem = ElemType(row, col);
/* head的所有指针都指向自己 */
m_pHead->up = m_pHead->left = m_pHead->down = m_pHead->right = m_pHead;
/* 列指针初始化时上下指针指向自己 */
for (int i = 0; i < col; ++i) {
m_pCols[i].elem = ElemType(0, i);
m_pCols[i].left = m_pHead;
m_pCols[i].right = m_pHead->right;
m_pCols[i].left->right = m_pCols[i].right->left = m_pCols[i].up = m_pCols[i].down = &m_pCols[i];
m_pSz[i] = 0;
}
/* 行指针初始化时左右指针指向自己,并且因为是前插,所有要倒序遍历 */
for (int i = row - 1; i >= 0; --i) {
m_pRows[i].elem = ElemType(i, col);
m_pRows[i].up = m_pHead;
m_pRows[i].down = m_pHead->down;
m_pRows[i].up->down = m_pRows[i].down->up = m_pRows[i].left = m_pRows[i].right = &m_pRows[i];
}
}
}
inline int DLX::getMinColPos() {
int min = 0x3f3f3f3f;
int col = -1;
for (DLXNode * p = m_pHead->left; p != m_pHead; p = p->left) {
if (m_pSz[p->elem.c] < min) {
min = m_pSz[p->elem.c];
col = p->elem.c;
}
}
return col;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int N, M;
cin >> N >> M;
int cnt = 0;
vector > mtx(N, vector(M, 0));
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
cin >> mtx[i][j];
if (mtx[i][j]) {
++cnt;
}
}
}
int row = cnt + (81 - cnt) * 9;
int col = 324;
cnt = 0;
DLX dlx(row, col);
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
if (mtx[i][j]) {
dlx.addNode((cnt), (i) * 9 + (j));
dlx.addNode((cnt), (i) * 9 + 81 + mtx[i][j] - 1);
dlx.addNode((cnt), (j) * 9 + 162 + mtx[i][j] - 1);
dlx.addNode((cnt), (i / 3 * 3 + j / 3) * 9 + 243 + mtx[i][j] - 1);
m[++cnt] = mtx[i][j];
}
else {
for (int k = 1; k <= 9; ++k) {
dlx.addNode((cnt), (i) * 9 + (j));
dlx.addNode((cnt), (i) * 9 + 81 + k - 1);
dlx.addNode((cnt), (j) * 9 + 162 + k - 1);
dlx.addNode((cnt), (i / 3 * 3 + j / 3) * 9 + 243 + k - 1);
m[++cnt] = k;
}
}
}
}
if (!dlx.dance(0)) {
cout << "数独无解";
}
return 0;
}
/*
9 9
7 6 0 5 9 3 0 0 0
9 0 1 0 0 0 5 0 0
0 3 0 4 0 0 0 9 0
1 0 8 0 2 0 0 0 4
4 0 0 3 0 9 0 0 1
2 0 0 0 1 0 6 0 9
0 8 0 0 0 6 0 2 0
0 0 4 0 0 0 8 0 7
0 0 0 7 8 5 0 1 0
*/