刷華爲的機試題(傳送門:數獨),刷到了一個關於數獨的題目,以爲數獨還有什麼特殊的解,自己寫了個減枝的dfs過了83%的數據,但是好多同學都有同樣的問題,估計使題目的問題把,這題有多解但是做法不同,就有不同的答案,但是答案都是正確的,然後test有隻有一個這就很惱火,所以就假裝我這是正確的吧。
以前聽說過數獨但是一直沒有深入學習過,今天藉着刷題學習了一下關於數獨的知識,想不到什麼高效的解法,就寫了個dfs+減枝,居然能拋出結果出來,難以置信具體思路看代碼吧,感覺跑起來挺快的:
#include<bits/stdc++.h>
#include<hash_set>
#define ll long long
#define qq printf("QAQ\n");
#define setit set<int>::iterator
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
int mp[10][10];
bool visrow[10][10],viscol[10][10],vispla[10][10],flag;
/* visrow 行標記 i行1-9那些數已經出現過了
viscol 列標記 vislpa宮標記
*/
void dfs(int pos)//pos表示當前位置
{
//printf("pos=%d\n",pos);
if(flag)return ;//已經找到正確答案了(註釋可以得到全部答案)
if(pos==81){//到達出口
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
printf("%d%c",mp[i][j],j==9?'\n':' ');
flag=1;
}
int x=pos/9+1,y=pos%9+1;//根據pos計算行類座標
int pla=((x-1)/3)*3+(y-1)/3+1;//計算宮編號
if(mp[x][y])dfs(pos+1);
else {
for(int i=1;i<=9;i++)
{
if(visrow[x][i]||viscol[y][i]||vispla[pla][i])continue;//行列宮已經出現過這個數了
visrow[x][i]=1;
viscol[y][i]=1;
vispla[pla][i]=1;
mp[x][y]=i;
dfs(pos+1);//dfs 枚舉操作
mp[x][y]=0;
visrow[x][i]=0;
viscol[y][i]=0;
vispla[pla][i]=0;
}
}
}
int main()
{
memset(visrow,0,sizeof visrow);
memset(viscol,0,sizeof viscol);
memset(vispla,0,sizeof vispla);
for(int i=1; i<=9; i++)
for(int j=1; j<=9; j++)
{
scanf("%d",&mp[i][j]);//已知輸入
if(!mp[i][j])continue;
visrow[i][mp[i][j]]=1;
viscol[j][mp[i][j]]=1;
vispla[((i-1)/3)*3+(j-1)/3+1][mp[i][j]]=1;//可以好好體會一下計算宮的公式
}
flag=0;
clock_t t1,t2;
t1=clock();
dfs(0);
t2=clock();
printf("time spent:%d\n",t2-t1);
return 0;
}
/*
世界最難數獨 跑的超級快
8 0 0 0 0 0 0 0 0
0 0 3 6 0 0 0 0 0
0 7 0 0 9 0 2 0 0
0 5 0 0 0 7 0 0 0
0 0 0 0 4 5 7 0 0
0 0 0 1 0 0 0 3 0
0 0 1 0 0 0 0 6 8
0 0 8 5 0 0 0 1 0
0 9 0 0 0 0 4 0 0
*/