题目描述:数独游戏, 9*9的棋盘上, 同一行1-9不能出现重复的, 同一列也是, 然后整个棋盘分成九份, 每个3*3的格子内也不能出现重复的.
题目分析: DFS深搜即可, 然后可以用二进制进行状态压缩节省时间. 有人说直接暴力也可以过.
还有第二个优化的地方, 不用每次都遍历找空的格子.直接保存每个空的格子的位置, 然后回溯即可.
说一下怎么压缩吧
一行九个数, 可以压缩成一个整数, 第几位是1表示几已经出现过. 0表示未出现.
列也可以, 方格也可以, 这样每个空的三个依赖就可以用三个整数表示. 然后让三个数按位或, 三个数或完之后依然是0, 表示这个数都没有出现.表示可以用.
这个题坑的地方在于输入, 要按字符读. 比较麻烦.
一开始超时了两次, 我以为优化的不够好, 后来发现读题不细心, 两个输入之间还有个空行……, 这是故意的吧. 因为我用getchar读的, 所以一直等着输入呢, 就超时了, 如果用cin就不会出现这个情况.
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef pair<int, int> P;
int R[10], C[10], A[10][10];
int mp[10][10];
int cnt;
P Next[90];
int Case;
int read()
{
memset(A, 0, sizeof A);
memset(R, 0, sizeof R);
memset(C, 0, sizeof C);
char ch;
if(Case)
if(getchar() == EOF) return -1;
cnt = 0;
for(int i=0; i<9; ++i)
{
for(int j=0; j<9; j++)
{
ch = getchar();
getchar();
if(ch == '?')
{
mp[i][j] = 0;
Next[cnt++] = P(i, j);
}
else
{
mp[i][j] = ch - '0';
R[i] |= (1 << mp[i][j]);
C[j] |= (1 << mp[i][j]);
A[i/3][j/3] |= (1 << mp[i][j]);
}
}
}
return 1;
}
bool dfs(int pos)
{
if(pos == cnt) return true;
int x = Next[pos].first, y = Next[pos].second;
int a = (x/3);
int b = y/3;
int t = (R[x] | C[y] | A[a][b]);
for(int i=1; i<10; ++i)
{
if((t >> i) & 1) continue;
R[x] |= (1 << i);
C[y] |= (1 << i);
A[a][b] |= (1 << i);
mp[x][y] = i;
if(dfs(pos+1)) return true;
mp[x][y] = 0;
R[x] ^= (1 << i);
C[y] ^= (1 << i);
A[a][b] ^= (1 << i);
}
return false;
}
int main()
{
while(read() != -1)
{
dfs(0);
if(Case++) printf("\n");
for(int i=0; i<9; ++i)
{
for(int j=0; j<9; ++j)
if(j == 0) printf("%d", mp[i][j]);
else printf(" %d", mp[i][j]);
printf("\n");
}
}
return 0;
}