DFS专题合集:
据说填充数独用DLX是最快的,笔者不会DLX,故使用DFS并无限优化。
在这里只说明一些优化操作。
一:优化顺序:
同9*9的数独,我们找到可以填充字母最少的格点,从这个点开始DFS,分支数目最少。
二:可行性剪枝
1:按空格剪枝:
我们找到每个为填充字母的格点,判断其是否可以填充字母,如果不可以,则直接剪枝;如果只可以填充一个字母,则将其填入。
2:按行剪枝:
枚举每行,如果这一行有字母不可以填充,则直接剪枝,如果只可以填充一个字母,则填入。
3:按列剪枝:
枚举每列,如果这一行有字母不可以填充,则直接剪枝,如果只可以填充一个字母,则填入。
4:按16宫格剪枝
枚举每个16宫格,如果这一行有字母不可以填充,则直接剪枝,如果只可以填充一个字母,则填入。
三:判断边界:
当格子内没有空格时,则为一组可行方案。
四:题目以及AC代码:
洛谷双倍经验!
两道黑题,也是第一次做黑题。
题目传送门:
注意细节:UVA测评不允许输出最后有多余的空格或者换行。
SP1110 AC代码:
#include<iostream>
#include<cstring>
#define AC return 0;
using namespace std;
const int N=16;
int map[1<<N],ones[1<<N];
char str[N][N+1];
int state[N][N];
char backstr[N*N+1][N][N+1];
int backstate[N*N+1][N][N],backstate2[N*N+1][N][N];
int lowbit(int x)
{
return x&-x;
}
void draw(int x,int y,int c)
{
str[x][y]='A'+c;
for(int i=0;i<N;i++)
{
state[i][y] &= ~(1<<c);
state[x][i] &= ~(1<<c);
}
int sx=x/4*4,sy=y/4*4;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
state[sx+i][sy+j] &= ~(1<<c);
state[x][y]=1<<c;
}
bool dfs(int cnt)
{
if(!cnt) return 1;
int kcnt=cnt;
memcpy(backstr[kcnt],str,sizeof(str));
memcpy(backstate[kcnt],state,sizeof(state));
//枚举每个空格是否有格子不能填,不能填直接剪枝,只能填一个就填上。
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(str[i][j]=='-')
{
if(!state[i][j])
{
memcpy(str,backstr[kcnt],sizeof(str));
memcpy(state,backstate[kcnt],sizeof(state));
return 0;
}
if(ones[state[i][j]]==1)
{
draw(i,j,map[state[i][j]]);