和数独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的大佬

京公网安备 11010502036488号