又是一个水数据的搜索……不过还是剪枝做了做 剪枝大法好啊!好多几百ms的 剪出来个0ms 顿感欣慰
不过看discuss 3074 Sudoku数据更强大 傻傻的去做了 最后T的实在不行的时候看到discuss说用dance links。。。呵呵了= = 只在当初听说xiao爷学了一阵子。。我还是慢慢搞吧= =有兴趣的可以去看看
回归此题。。我是存了三个数组分别标记行中哪些数能用 列中哪些数能用 子数独中哪些数能用 然后大胆的搜吧。。
剪枝我在每个白块后面加了个邻接表 刚才去掉一交跑了400多。。。也挺管用。。。吓死宝宝了……
代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
typedef struct Point
{
int data,next;
}Point;
bool vsx[10][10],vsy[10][10],vshl[10][10];//行、列、子数独标记
char mp[10][11];
Point num[733];
int head[10][10];//空白块后的邻接表
int tp;
int gethl(int x,int y)//横总坐标转换子数独块下标。。推出来的
{
return ((x+2)/3-1)*3 + (y+2)/3;
}
bool dfs(int x,int y)
{
if(x == 9 && y == 9) return true;
int i,data;
x = (y == 9)? (x+1): x;
y = (y == 9)? 1: (y+1);//y遍历到9时换行
if(mp[x][y] != '0') return dfs(x,y);
for(i = head[x][y]; i != -1; i = num[i].next)
{
data = num[i].data;
if(vsx[x][data] || vsy[y][data] || vshl[gethl(x,y)][data]) continue;
vsx[x][data] = vsy[y][data] = vshl[gethl(x,y)][data] = 1;
mp[x][y] = '0'+data;
if(dfs(x,y)) return true;
vsx[x][data] = vsy[y][data] = vshl[gethl(x,y)][data] = 0;
}
mp[x][y] = '0';
return false;
}
int main()
{
int t,i,j,k;
scanf("%d",&t);
while(t--)
{
memset(vsx,0,sizeof(vsx));
memset(vsy,0,sizeof(vsy));
memset(vshl,0,sizeof(vshl));
memset(head,-1,sizeof(head));
tp = 0;
for(i = 1; i <= 9; ++i)
{
scanf("%s",mp[i]+1);
for(j = 1; j <= 9; ++j)
if(mp[i][j] != '0')
{
vsx[i][mp[i][j]-'0'] = 1;
vsy[j][mp[i][j]-'0'] = 1;
vshl[gethl(i,j)][mp[i][j]-'0'] = 1;
}
}
for(i = 1; i <= 9; ++i)
for(j = 1; j <= 9; ++j)
{
if(mp[i][j] != '0') continue;
for(k = 1; k <= 9; ++k)
if(!vsx[i][k] && !vsy[j][k] && !vshl[gethl(i,j)][k])
{
num[tp].data = k;
num[tp].next = head[i][j];
head[i][j] = tp++;
}
}
dfs(1,0);
for(i = 1; i <= 9; ++i) printf("%s\n",mp[i]+1);
}
return 0;
}
本文介绍了一个使用剪枝算法解决数独问题的方法,并通过添加邻接表来提高效率。详细解释了如何利用行、列、子数独标记以及邻接表来减少搜索空间,最终实现快速求解数独。
2298

被折叠的 条评论
为什么被折叠?



