和数独1差不多--dancing link算法等会学完会有博客的QAQ,下面是爆搜解法.
数独1的代码也就1百多行QWQ,数独2也才200多行,可惜蒟蒻代码打的少,导致码力十分弱,所以写下博客为自己壮胆QAQ.
数独2题目是:
请你将一个16x16的数独填写完整,使得每行、每列、每个4x4十六宫格内字母A~P均恰好出现一次。保证每个输入只有唯一解决方案。
也就是按题目模拟以及爆搜即可.
下面讲下剪枝:
剪枝1:对于每个空格假如填不了任何字母则无解,假如只能填一个字母那就直接填这个字母.
剪枝2:对于每一行而言,假如每个字母不能出现在任何一个位子则无解.假如那个位子只能填一个字母则直接填上.
剪枝3:对于每一列而言,假如每个字母不能出现在任何一个位子则无解.假如那个位子只能填一个字母则直接填上.
剪枝4:对于每个16宫格而言,假如每个字母不能出现在任何一个位子则无解.假如那个位子只能填一个字母则直接填上.
剪枝5:每次选择空格时,选择方案数最小的来填.
emmm...下面就到了艰难的代码时刻QAQ
#include <bits/stdc++.h> using namespace std; const int N=16; int mp[1<<(N+1)+1],ones[1<<(N+1)+1],state[N+1][N+1],bstate[N*N+1][N+1][N+1],bstate2[N*N+1][N+1][N+1]; char str[N][N+1],bstr[N*N+1][N+1][N+1]; void init() { for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { state[i][j]=(1<<N)-1; } } } inline 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[x][i]&=~(1<<c); state[i][y]&=~(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 true; int bcnt=cnt; memcpy(bstr[bcnt],str,sizeof str); memcpy(bstate[bcnt],state,sizeof state); //剪枝1: for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { if(str[i][j]=='-') { if(!state[i][j]) { memcpy(state,bstate[bcnt],sizeof state); memcpy(str,bstr[bcnt],sizeof str); return false; } if(ones[state[i][j]]==1) { draw(i,j,mp[state[i][j]]); cnt--; } } } } //剪枝2: for(int i=0;i<N;i++)//枚举每一行 { int ck=0;int s=0;int sand=(1<<N)-1; for(int j=0;j<N;j++)//枚举每一行的每一个数 { sand&=~(state[i][j]&s);//排除多个选择的数 s|=state[i][j];//看下是否全部覆盖 if(str[i][j]!='-') ck|=state[i][j];//排除已经填过的数 } if(s!=(1<<N)-1) { memcpy(state,bstate[bcnt],sizeof state); memcpy(str,bstr[bcnt],sizeof str); return false; } for(int j=sand;j;j-=lowbit(j)) { int t=lowbit(j); if(!(t&ck)) { for(int k=0;k<N;k++) { if (state[i][k]&t) { draw(i,k,mp[t]); cnt--; break; } } } } } //剪枝3: for(int i=0;i<N;i++)//枚举每一列 { int ck=0;int s=0;int sand=(1<<N)-1; for(int j=0;j<N;j++)//枚举每一行的每一个数 { sand&=~(state[j][i]&s);//排除多个选择的数 s|=state[j][i];//看下是否全部覆盖 if(str[j][i]!='-') ck|=state[j][i];//排除已经填过的数 } if(s!=(1<<N)-1) { memcpy(state,bstate[bcnt],sizeof state); memcpy(str,bstr[bcnt],sizeof str); return false; } for(int j=sand;j;j-=lowbit(j)) { int t=lowbit(j); if(!(t&ck)) { for(int k=0;k<N;k++) { if (state[k][i]&t) { draw(k,i,mp[t]); cnt--; break; } } } } } //剪枝4: for(int i=0;i<N;i++)//枚举16宫格的编号 { int ck=0;int s=0;int sand=(1<<N)-1; for(int j=0;j<N;j++)//枚举在16宫格的每个位子 { int sx=i/4*4,sy=i%4*4; int dx=j/4,dy=j%4; sand&=~(state[sx+dx][sy+dy]&s);//排除多个选择的数 s|=state[sx+dx][sy+dy];//看下是否全部覆盖 if(str[sx+dx][sy+dy]!='-') ck|=state[sx+dx][sy+dy];//排除已经填过的数 } if(s!=(1<<N)-1) { memcpy(state,bstate[bcnt],sizeof state); memcpy(str,bstr[bcnt],sizeof str); return false; } for(int j=sand;j;j-=lowbit(j)) { int t=lowbit(j); if(!(t&ck)) { for(int k=0;k<N;k++) { int sx=i/4 *4,sy=i%4*4; int dx=k/4,dy=k%4; if (state[sx+dx][sy+dy]&t) { draw(sx+dx,sy+dy,mp[t]); cnt--; break; } } } } } //剪枝5: int x,y,sum=30; for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { if(str[i][j]=='-'&&ones[state[i][j]]<sum) { sum=ones[state[i][j]]; x=i,y=j; } } } if(!cnt) return true; memcpy(bstate2[bcnt],state,sizeof state); for (int i = state[x][y]; i; i -= lowbit(i)) { memcpy(state,bstate2[bcnt],sizeof state); draw(x,y,mp[lowbit(i)]); if(dfs(cnt - 1)) return true; } memcpy(state,bstate[bcnt],sizeof state); memcpy(str,bstr[bcnt],sizeof str); return false; } int main() { for(int i=0;i<N;i++) mp[1<<i]=i; for(int i=1;i<1<<N;i++) { for(int j=i;j;j-=lowbit(j)) { ones[i]++; } } while(cin>>str[0]) { > int cnt=0; for(int i=1;i<N;i++) cin>>str[i]; init(); for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { if(str[i][j]!='-') { draw(i,j,str[i][j]-'A'); } else cnt++; } } dfs(cnt); for(int i=0;i<N;i++) cout<<str[i]<<endl; cout<<endl; } return 0; }
感谢帮我debug的大佬