靶形数独(恶心啊)

这道题。。重点是数独的性质

(原谅我第一次做没注意)
数独:每个区间,每行,每列数字都不能重复

然后。。为了方便计算,先打三个表:
#include<bits/stdc++.h>
using namespace std;
struct node { int l,r;}b[20]={};//这个。。好像没什么用,最开始加的。。后来发现用不上
int a[20][20]={},d[20][20]={}//这个点上的分值,
c[10][10]={0,0,0,0,0,0,0,0,0,0,
0,1,1,1,2,2,2,3,3,3,
0,1,1,1,2,2,2,3,3,3,
0,1,1,1,2,2,2,3,3,3,
0,4,4,4,5,5,5,6,6,6,
0,4,4,4,5,5,5,6,6,6,
0,4,4,4,5,5,5,6,6,6,
0,7,7,7,8,8,8,9,9,9,
0,7,7,7,8,8,8,9,9,9,
0,7,7,7,8,8,8,9,9,9};//这个点属于哪一个区间


for(int i=1;i<=9;i++) 
for(int j=1;j<=9;j++) 
{	
scanf("%d",&a[i][j]); 
if (i==5&&j==5) 
{ d[i][j]=10; continue; } 
if (i>=4&&j>=4&&i<=6&&j<=6) 
{ d[i][j]=9; continue; } 
if (i>=3&&j>=3&&i<=7&&j<=7) 
{ d[i][j]=8; continue; } 
if (i>=2&&j>=2&&i<=8&&j<=8) 
{ d[i][j]=7; continue; } 
d[i][j]=6; 
} 
b[1].l=b[2].l=b[3].l=1;
b[1].r=b[4].r=b[7].r=1;
b[4].l=b[5].l=b[6].l=4;
b[2].r=b[5].r=b[8].r=4;
b[7].l=b[8].l=b[9].l=7;
b[3].r=b[6].r=b[9].r=7;

接着来三个标记数组:
bool visg[20][20]={}//每个区间,visx[20][20]={}//每行,visy[20][20]={}//每列;

因为输入会有给定的值,所以先处理一遍:

for(int i=1;i<=9;i++)
	 {
	 	for(int j=1;j<=9;j++)
	 	 {
	 	 	if (a[i][j]!=0)
			 {
			 	visg[c[i][j]][a[i][j]]=false;
			 	visx[i][a[i][j]]=false;
	                        visy[j][a[i][j]]=false;
			 } 
	 	 }
	 } 

这个搜索就很有趣了:

 
 
inline int ask(){  
 int k=0;  
   for(int i=1;i<=9;i++)  
     for(int j=1;j<=9;j++) 
      k+=a[i][j]*d[i][j];  
  return k;
}
inline void find(int x,int y){
        if (x==10) //边界
          {
             ans=max(ans,ask());
             return ;//这个return千万不要忘(最开始忘了。。然后。。停不下来,最后RE)
         }
     int st[100]={},t=0;
    if (a[x][y]==0)//需要填数
    {
     for(int i=1;i<=9;i++)
      if (visg[c[x][y]][i]&&visx[x][i]&&visy[y][i])//注意是都满足才能用(最开始满足一个用,还查了半天错)
        st[++t]=i; //找能填的数
     for(int i=1;i<=t;i++)
       {
          a[x][y]=st[i];
          visg[c[x][y]][st[i]]=false;
          visx[x][st[i]]=false;
          visy[y][st[i]]=false;
          if (y==9) find(x+1,1);//换行处理
            else find(x,y+1);
         a[x][y]=0;//最开始偷懒这句没加,想着下次循环会覆盖的。。然而。。
         visg[c[x][y]][st[i]]=true; visx[x][st[i]]=true; visy[y][st[i]]=true;
       } //回溯
    }
   else //不需要填数
     if (y==9) find(x+1,1); else find(x,y+1);}
调用并输出:
find(1,1);
    if (ans!=0) printf("%d",ans);//数独有解
	 else printf("-1");//数独无解
memset(visg,true,sizeof(visg));
memset(visx,true,sizeof(visx));
memset(visy,true,sizeof(visy));//这些初始值自然是不能忘的

总结:
 这种大搜索第一注意边界,第二注意初值,第三能加的剪枝尽量加(虽然这道题没什么剪枝)

ps:回溯时前往不要偷懒。。不然死的很惨

猜你喜欢

转载自blog.csdn.net/qq_40716114/article/details/80313866