Sudoku
Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu
Submit
Status
Description
In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example,
. 2 7 3 8 . . 1 .
. 1 . . . 6 7 3 5
. . . . . . . 2 9
3 . 5 6 9 2 . 8 .
. . . . . . . . .
. 6 . 1 7 4 5 . 3
6 4 . . . . . . .
9 5 1 8 . . . 7 .
. 8 . . 6 5 3 4 .
Given some of the numbers in the grid, your goal is to determine the remaining numbers such that the numbers 1 through 9 appear exactly once in (1) each of nine 3 × 3 subgrids, (2) each of the nine rows, and (3) each of the nine columns.
Input
The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word “end”.
Output
For each test case, print a line representing the completed Sudoku puzzle.
Sample Input
.2738..1..1…6735…….293.5692.8………..6.1745.364…….9518…7..8..6534.
……52..8.4……3…9…5.1…6..2..7……..3…..6…1……….7.4…….3.
end
Sample Output
527389416819426735436751829375692184194538267268174593643217958951843672782965341
416837529982465371735129468571298643293746185864351297647913852359682714128574936
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxnode = 300010;
const int MaxM = 1010;
const int MaxN = 1010;
bool rowmark[1010];
struct DLX
{
int n,m,size;
int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];
//U D R L用来记录某个标号的节点的上下左右节点的标号
//Row Col用来记录某个标号的节点在矩阵中的行号和列号
int H[MaxN], S[MaxM];
//H是行头 S用来保存某一列中1的数量
int ansd, ans[MaxN];
void init(int _n,int _m)
{
n = _n;
m = _m;
//初始化列头
for(int i = 0;i <= m;i++)
{
S[i] = 0;
U[i] = D[i] = i;
L[i] = i-1;
R[i] = i+1;
}
R[m] = 0; L[0] = m;
size = m;
for(int i = 1;i <= n;i++)
H[i] = -1;
}
void Link(int r,int c)
{
++S[Col[++size]=c];
Row[size] = r;
D[size] = D[c];
U[D[c]] = size;
U[size] = c;
D[c] = size;
if(H[r] < 0)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;
}
}
//对某一列进行删除 同时删除列中为1的行
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)
{
for(int i = U[c];i != c;i = U[i])
for(int j = L[i];j != i;j = L[j])
{
U[D[j]]=D[U[j]]=j;
++S[Col[j]];
}
L[R[c]] = R[L[c]] = c;
}
//d为递归深度
bool Dance(int d)
{
if(R[0] == 0)
{
for(int i=1;i<=81;i++)
printf("%d",ans[i]);
printf("\n");
return true;
}
int c = R[0];
//一个优化 找到列中包含1最多的列 因为这样有助于减少递归深度 (很显然1多了 删掉的行也多 矩阵缩小得就快)
for(int i = R[0];i != 0;i = R[i])
if(S[i] < S[c])
c = i;
remove(c);
//搜索
for(int i = D[c];i != c;i = D[i])
{
//if(rowmark[i]!=0)
// continue;
ans[(Row[i]-1)/9+1] = (Row[i]-1)%9+1;
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;
}
};
DLX g;
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
char str[90];
while(scanf("%s",str+1))
{
if(!strcmp(str+1,"end"))break;
g.init(9*9*9,4*9*9);
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
int id=(i-1)*9+j;
for(int k=1;k<=9;k++)
{
if(str[id]=='.'||(str[id]-'0'==k))
{
int xx=(id-1)*9+k;
g.Link(xx,id);
g.Link(xx,9*9+(i-1)*9+k);
g.Link(xx,2*9*9+(j-1)*9+k);
g.Link(xx,3*9*9+((i-1)/3*3*9+(j-1)/3*9+k));
}
}
}
}
g.Dance(0);
}
}