数独深搜踩的坑
2020年4月2日



原题链接http://poj.org/problem?id=2676和http://poj.org/problem?id=2918
两题一样的改个输出格式就行
本来想跟着书练深搜剪枝,这是书上这一块第一题,本以为dfs会了其实还是不理解,前前后后改了四个版本,折腾了一个上午。
思路
poj上四个数独题,这是最简单的两道,优化想法来自书本。改边搜索顺序,先搜索已知数多的行。
丑陋的代码1.0
以每一格为一个阶段,出口和进一步深搜的先决条件没设计好。
递归返回到原来调用它的地方这里少了个col<=9竟会导致col无限递增,在这种情况下:某一行的最后一格是填过的,从这里递归下去遇到某一不合法状态又回溯到这里,然后这个if回溯的时候居然会再判断一次?

后补:网上别人的写法,所以其实是自己没分清情况,这一切都是一个美妙的误会……

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 25
#define INF 0x3f3f3f3f
using namespace std;
char mp[MAXN][MAXN];
struct Data{int row,cnt;}d[MAXN];
int visr[MAXN][MAXN],visc[MAXN][MAXN],flag;
bool cmp(Data a,Data b){
return a.cnt>b.cnt;
}
void dfs(int deep,int row,int col){
// printf("%d %d\n",row,col);
// printf("%s\n",mp[row]+1);
// if(col>10)return;
if(col>=10&&deep<10)dfs(deep+1,d[deep+1].row,1);
if(deep>=10&&col>=10){
if(flag==0){
for(int i=1;i<=9;++i){
printf("%s",mp[i]+1);
printf("\n");
}flag=1;
}
return;
}
if(mp[row][col]!='0'&&col<=9)dfs(deep,row,col+1);
else{
for(int k=1;k<=10;++k){
// printf("%d %d\n",visr[row][2],visc[col][2]);
// printf("k:%d %d %d %d %d\n",k,visr[row][k],visc[col][k],row,col);
if(k==10)return;
if(visr[row][k]||visc[col][k])continue;
int mark=0,m=(row-1)/3*3+1,n=(col-1)/3*3+1;
for(int i=m;i<m+3;++i)
for(int j=n;j<n+3;++j)if(mp[i][j]==k+'0'){mark=1;break;}
if(mark)continue;
mp[row][col]=k+'0';
visr[row][k]=visc[col][k]=1;
dfs(deep,row,col+1);
visr[row][k]=visc[col][k]=0,mp[row][col]='0';
}
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
memset(mp,0,sizeof(mp));
memset(visc,0,sizeof(visc));
memset(visr,0,sizeof(visr));
memset(d,0,sizeof(d));
for(int i=1;i<=9;++i){scanf("%s",mp[i]+1);d[i].row=i;}
for(int i=1;i<=9;++i)
for(int j=1;j<=9;++j){
if(mp[i][j]!='0'){visr[i][mp[i][j]-'0']=visc[j][mp[i][j]-'0']=2;d[i].cnt++;}
}
sort(d+1,d+10,cmp);
flag=0;
dfs(1,d[1].row,1);
}
}丑陋的代码2.0
代码补贴了,出口和查重都搞好了,但是题目要求是输出一个答案(神啊能不能告诉蒟蒻dfs怎么break呜呜呜)不会弄瞎整,就是只输出第一个答案,后面继续dfs,妥妥的t了
丑陋的代码3.0
开始怀疑这个优化,换了个思路,以一整行为阶段,写不下去了,不会回溯,不贴代码了
丑陋的代码4.0
老思路,整个flag疯狂return,ac了,time当然是非常不好看

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 25
#define INF 0x3f3f3f3f
using namespace std;
char mp[MAXN][MAXN];
struct Data{int row,cnt;}d[MAXN];
int visr[MAXN][MAXN],visc[MAXN][MAXN],flag;
bool cmp(Data a,Data b){
return a.cnt>b.cnt;
}
void dfs(int deep,int row,int col){
// printf("%d %d\n",row,col);
// printf("%s\n",mp[row]+1);
// if(col>10)return;
if(flag) return;
if(col>=10&&deep<10)dfs(deep+1,d[deep+1].row,1);
if(deep>=10&&col>=10){
if(flag==0){
for(int i=1;i<=9;++i){
printf("%s",mp[i]+1);
printf("\n");
}flag=1;
}
return;
}
if(flag) return;
if(mp[row][col]!='0'&&col<=9)dfs(deep,row,col+1);
else{
for(int k=1;k<=10;++k){
// printf("%d %d\n",visr[row][2],visc[col][2]);
// printf("k:%d %d %d %d %d\n",k,visr[row][k],visc[col][k],row,col);
if(k==10)return;
if(visr[row][k]||visc[col][k])continue;
int mark=0,m=(row-1)/3*3+1,n=(col-1)/3*3+1;
for(int i=m;i<m+3;++i)
for(int j=n;j<n+3;++j)if(mp[i][j]==k+'0'){mark=1;break;}
if(mark)continue;
mp[row][col]=k+'0';
visr[row][k]=visc[col][k]=1;
if(flag) return;
dfs(deep,row,col+1);
if(flag) return;
visr[row][k]=visc[col][k]=0,mp[row][col]='0';
}
if(flag) return;
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
memset(mp,0,sizeof(mp));
memset(visc,0,sizeof(visc));
memset(visr,0,sizeof(visr));
memset(d,0,sizeof(d));
for(int i=1;i<=9;++i){scanf("%s",mp[i]+1);d[i].row=i;}
for(int i=1;i<=9;++i)
for(int j=1;j<=9;++j){
if(mp[i][j]!='0'){visr[i][mp[i][j]-'0']=visc[j][mp[i][j]-'0']=2;d[i].cnt++;}
}
sort(d+1,d+10,cmp);
flag=0;
dfs(1,d[1].row,1);
}
}啊,神犇是怎么做到2676time0ms的,以后有空接着优化。嗯…大概……
Views: 151
上一篇
如何下载钉钉直播回放
下一篇