靶形数独

 

小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。

靶形数独的方格同普通数独一样,在 99 格宽×99 格高的大九宫格中有99 个 33 格宽×33 格高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 11 到 99的数字。每个数字在每个小九宫格内不能重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。(如图)

上图具体的分值分布是:最里面一格(黄色区域)为 1010 分,黄色区域外面的一圈(红色区域)每个格子为99分,再外面一圈(蓝色区域)每个格子为88 分,蓝色区域外面一圈(棕色区域)每个格子为77分,最外面一圈(白色区域)每个格子为66分,如上图所示。比赛的要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和

总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 2829。游戏规定,将以总分数的高低决出胜负。

由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能够得到的最高分数。

输入输出格式

输入格式:

 

一共 99 行。每行99个整数(每个数都在 0-909 的范围内),表示一个尚未填满的数独方格,未填的空格用“00”表示。每两个数字之间用一个空格隔开。

 

输出格式:

 

输出共 11 行。输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数-11。

 

1.搜索顺序

作者: 学无止境 更新时间: 2018-01-31 23:27  在Ta的博客查看  27 


本人蒟蒻,发个蒟蒻看得懂的题解~~

dfs代码最终效率不高——2000ms——3000多ms,(但是AC了,或许是数据水吧

大家玩过数独(没玩过的先了解规则去吧)

我的思路是dfs(不打表),用一个序列s[ ]保存要填的点,dfs携带的参数就是要填写的点的坐标:

s[ i ][0]与s[ i ][1]存点的坐标,s[ i ][2]存点的分值,s[ i ][3]存点的所在宫(我用函数现生成,避免了打表)。

需要注意的有如下几点:

一、dfs过程中就判断数能不能放,别放到最后判断(这一条可能是废话)实现方法用三个数组分别存各行、列、宫每个数字的状态(0表示没填过,1表示填过)

(重要)二、dfs层数与0的个数有关,层数太多就TLE了,我们知道,一行中填过的数字越多,需要填的数越少,就意味着dfs层数越少!所以,我们先填0的数量少的行。(详细实现见代码)

不懂的看这:)

0 0 0 0 0 0 0 0 0    //这一行有9个0
1 0 0 0 0 5 9 0 0  //这一行有6个0
0 0 0 2 0 0 0 8 0 //这一行有7个0
0 0 5 0 2 0 0 0 3 //这一行有6个0
0 0 0 0 0 0 6 4 8 //这一行有6个0
4 1 3 0 0 0 0 0 0 //这一行有6个0
0 0 7 0 0 2 0 9 0 //这一行有6个0
2 0 1 0 6 0 8 0 4 //这一行有4个0
0 8 0 5 0 4 0 1 2//这一行有4个0

在这个例子中,从第一行到第九行dfs的话,那么dfs第一层就有9种情况!!!根据dfs的原理,从第一层9种情况开始拓展,那么时间就要花很多。而若从第8层开始只有4种情况,搜索需要的时间就大大减少。TLE再见!!

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=17;
 6 const int maxm=107;
 7 struct Ha{
 8   int pos,sum;
 9 }ha[maxn];
10 struct Rdy{
11   int x;int y;
12 }rdy[maxm];
13 bool hang[maxn][maxn],lie[maxn][maxn],gong[maxn][maxn][maxn];
14 int map[maxn][maxn];
15 int ans=-1,rdy_top,cnt;
16 bool cmp(Ha a,Ha b){
17   return a.sum<b.sum;
18 }
19 int val(int x,int y){
20   if(x==0||y==0||x==8||y==8) return 6;
21   if(x==1||y==1||x==7||y==7) return 7;
22   if(x==2||y==2||x==6||y==6) return 8;
23   if(x==3||y==3||x==5||y==5) return 9;
24   return 10;
25 }
26 void dfs(int no,int num){
27   if(no==rdy_top+1){
28     ans=max(ans,num);
29   }
30   int xx=rdy[no].x;int yy=rdy[no].y;
31   for(int i=1;i<=9;i++){
32     if(!hang[xx][i]&&!lie[yy][i]&&!gong[xx/3][yy/3][i]){
33       hang[xx][i]=true;lie[yy][i]=true;gong[xx/3][yy/3][i]=true;
34       dfs(no+1,num+i*val(xx,yy));
35       hang[xx][i]=false;lie[yy][i]=false;gong[xx/3][yy/3][i]=false;
36     }
37   }
38 }
39 int main(){
40   for(int i=0;i<9;i++) ha[i].pos=i;
41   for(int i=0;i<9;i++){
42     for(int j=0;j<9;j++){
43       cin>>map[i][j];
44       if(map[i][j]==0) ha[i].sum++;
45     }
46   }
47   sort(ha,ha+9,cmp);
48   for(int i=0;i<9;i++){
49     for(int j=0;j<9;j++){
50       if(map[i][j]!=0){
51         hang[i][map[i][j]]=lie[j][map[i][j]]=gong[i/3][j/3][map[i][j]]=true;
52         cnt+=map[i][j]*val(i,j);
53       }
54     }
55   }
56   for(int u=0;u<9;u++){
57       int i=ha[u].pos;
58     for(int j=0;j<9;j++){
59       if(map[i][j]==0){
60         rdy[++rdy_top].x=i;rdy[rdy_top].y=j;
61       }
62     }
63   }
64   dfs(1,cnt);
65   cout<<ans<<endl;
66   return 0;
67 }

2.舞蹈链????https://www.cnblogs.com/grenet/p/3163550.html

3.作者: circle_star 更新时间: 2018-02-27 13:49  在Ta的博客查看  6 


二进制优化的数独, 具体做法 解释 cnt[i]就是统计i这个状态所能填的数字个数---它减lowbit的次数就是1出现的次数 num[i]就是lowbit所对应的数字

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int r[9],l[9],b[9];
 4 int cnt[512],num[512];
 5 int a[9][9];
 6 inline int g(int x, int y) {
 7     return ((x/3) * 3) + (y / 3);
 8 }
 9 void flip(int x,int y,int z){
10     r[x]^=1<<z;
11     l[y]^=1<<z;
12     b[g(x,y)]^=1<<z;
13 }
14 int pd(int x,int y){
15     if(x==4&&y==4){
16         return 10;
17     }else if(3<=x&&x<=5&&3<=y&&y<=5) return 9;
18     else if(2<=x&&x<=6&&2<=y&&y<=6) return 8;
19     else if(1<=x&&x<=7&&1<=y&&y<=7) return 7;
20     else if(0<=x&&x<=8&&0<=y&&y<=8) return 6;
21 }
22 int maxx=0;
23 bool dfs(int now,long long mark1) {
24     if (now == 0){
25         if(maxx<mark1){
26             maxx=mark1;
27         }
28         return 1;
29     }
30     int temp = 10, x, y;
31     for (int i = 0; i < 9; i++)
32         for (int j = 0; j < 9; j++) {
33             if (a[i][j] != -1 ) continue;
34             int val = r[i] & l[j] & b[g(i,j)];
35             if (!val) return 0;
36             if (cnt[val] < temp) {
37                 temp = cnt[val];
38                 x = i, y = j;
39             }
40         }
41     int flag=0;
42     int val = r[x] & l[y] & b[g(x, y)];
43     for (; val; val -= val&-val) {
44         int z = num[val&-val];
45         a[x][y] =  z + 1;
46         flip(x, y, z);
47         if (dfs(now - 1,mark1+pd(x,y)*(z+1))) flag=1;
48         flip(x, y, z);
49         a[x][y] = -1;
50     }
51     if(flag==1) return 1; 
52     return 0;
53 }
54 int main(){
55     int t=0;
56     for(int i=0;i<1<<9;i++) 
57         for(int j=i;j;j-=j&-j) cnt[i]++;
58     for(int i=0;i<9;i++){
59         num[1<<i]=i;
60     }
61     for(int i=0;i<9;i++) r[i]=l[i]=b[i]=(1<<9)-1;
62     long long sum=0;
63     for(int i=0;i<9;i++)
64      for(int j=0;j<9;j++){
65         cin>>a[i][j];
66         sum+=a[i][j]*pd(i,j);
67         if(a[i][j]!=0) flip(i,j,a[i][j]-1);
68         else  t++,a[i][j]=-1;
69      }
70     if(dfs(t,0)) 
71     cout<<maxx+sum;
72     else cout<<-1; 
73 } 

 

posted @ 2018-09-17 21:57  lcan  阅读(554)  评论(0编辑  收藏  举报