题意
数独游戏。
思路
部分固定的跳舞链
链接
http://poj.org/problem?id=3074
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int n = 9;
const int maxn = n * n * n + 10;
const int maxm = n * n * 3 + n * n + 10;
const int maxv = maxn * maxm;
struct DLX
{
int n, m, size; //行数、列数、节点数
int U[maxv], D[maxv], L[maxv], R[maxv], Row[maxv], Col[maxv]; //上、下、左、右指针,行、列号
int S[maxm], H[maxn]; //列的节点个数,行的头指针
int ansd, ans[maxn]; //答案栈
void init(int _n, int _m) //初始化函数
{
n = _n, m = _m;
for(int j= 0; j<= m; j++)
{
Row[j] = 0, Col[j] = j; //行、列号
U[j] = D[j] = j; //上下指针
S[j] = 0;
L[j] = j - 1, R[j] = j + 1; //左右指针
}
L[0] = m, R[m] = 0; //端点左右指针
size = m; //节点个数(初始 = 列数)(附加节点)
for(int i= 1; i<= n; i++) //行的头指针
H[i] = -1;
}
void link(int r, int c) //向链表中插入节点
{
size ++; //节点数目
Row[size] = r, Col[size] = c; //行号、列号
S[c] ++; //插入列链表
D[size] = D[c];
U[D[c]] = size;
D[c] = size;
U[size] = c;
if(H[r] == -1) H[r] = L[size] = R[size] = size; //将节点插入行链表
else{ //第一个节点之后
R[size] = R[H[r]];
L[R[H[r]]] = size;
L[size] = H[r];
R[H[r]] = size;
}
}
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 resume(int c) //恢复列函数(同时恢复列中节点所在的行
{
R[L[c]] = L[R[c]] = c; //列恢复
for(int i= U[c]; i!= c; i= U[i]) //恢复列中节点所在的行
for(int j= L[i]; j!= i; j= L[j])
{
U[D[j]] = j, D[U[j]] = j;
S[Col[j]] ++;
}
}
bool Dance(int d) //搜索函数
{
if(R[0] == 0) //剩余列为空,搜索成功
{
ansd = d;
return true;
}
int c = R[0]; //从节点少的列开始搜索,可以减少状态数
for(int j= R[0]; j!= 0; j= R[j])
if(S[j] < S[c]) c = j;
remove(c); //删除当前列
for(int i= D[c]; i!= c; i= D[i]) //遍历选取当前列中节点所在的行
{
ans[d] = Row[i]; //行号压入答案栈
for(int j= R[i]; j!= i; j= R[j]) remove(Col[j]); //删除行中节点对应的列
if(Dance(d+1)) return true; //向下一层搜索
for(int j= L[i]; j!= i; j= L[j]) resume(Col[j]); //搜索失败的话还原当前行
}
resume(c);
return false;
}
};
int G[n * n + 1][n * n + 1];
char in[n * n];
DLX g;
bool a[n + 1][n + 1], b[n + 1][n + 1], c[n + 1][n + 1];
int main(){
while(1){
scanf(" %s", in);
if(in[0] == 'e') break;
for(int i = 0; i < n * n; i++){
int x = i / 9 + 1, y = i % 9 + 1;
if(in[i] == '.') G[x][y] = 0;
else G[x][y] = in[i] - '0';
}
memset(a, false, sizeof a);
memset(b, false, sizeof b);
memset(c, false, sizeof c);
g.init(n * n * n, n * n * 3 + n * n);
//先把固定值建图
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(G[i][j] > 0){
a[i][G[i][j]] = b[j][G[i][j]] = c[(i - 1) / 3 * 3 + (j - 1) / 3 + 1][G[i][j]] = true;
g.link((i - 1) * n * n + (j - 1) * n + G[i][j], (i - 1) * n + G[i][j]);
g.link((i - 1) * n * n + (j - 1) * n + G[i][j], n * n + (j - 1) * n + G[i][j]);
g.link((i - 1) * n * n + (j - 1) * n + G[i][j], n * n * 2 + ((i - 1) / 3 * 3 + (j - 1) / 3 + 1 -1) * n + G[i][j]);
g.link((i - 1) * n * n + (j - 1) * n + G[i][j], n * n * 3 + (i - 1) * n + j);
}
}
}
//空白格建图
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(G[i][j] > 0) continue;//避开与固定值的冲突
for(int k = 1; k <= n; k++){
if(a[i][k] || b[j][k] || c[(i - 1) / 3 * 3 + (j - 1) / 3 + 1][k]) continue;
g.link((i - 1) * n * n + (j - 1) * n + k, (i - 1) * n + k);
g.link((i - 1) * n * n + (j - 1) * n + k, n * n + (j - 1) * n + k);
g.link((i - 1) * n * n + (j - 1) * n + k, n * n * 2 + ((i - 1) / 3 * 3 + (j - 1) / 3 + 1 -1) * n + k);
g.link((i - 1) * n * n + (j - 1) * n + k, n * n * 3 + (i - 1) * n + j);
}
}
}
g.Dance(0);
for(int i = 0; i < g.ansd; i++){
int x = (g.ans[i] - 1) / (n * n) + 1, y = (g.ans[i] - 1) % (n * n) / n + 1, k = (g.ans[i] - 1) % n + 1;
G[x][y] = k;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cout << G[i][j];
}
}
cout << endl;
}
return 0;
}