codevs 1174 靶形数独

来源:互联网 发布:护照制作软件 编辑:程序博客网 时间:2024/05/17 07:28

去题面的传送门
QAQ这道题已经调了很久了,一直是TLE
第一次交,codevs 35分,洛谷 70分(好吧看到这样子我还以为洛谷的数据水来着)
后来加了一个优化,codevs 95分,洛谷 80分(这才知道其实是codevs数据水)
优化是这样的:
一开始读入之后,把所有没有填的空位,它的所在行、列、九宫格里的已经填了的数字统计一下,放到结构体里,然后按照数字数量由大到小排序(所在区域已经填了的数字越多,越优先搜索),dfs时按照结构体顺序搜索,改掉原来一行一行地搜索
但是这样肯定不行,因为我还是T了(╮(╯▽╰)╭)
想想这样做有什么缺点:
①只统计了数字个数,而不是已经填了的数字的种类
②随着搜索的进行,下一个搜索的最优目标可能会改变,这时,初始时设定的已经排列好的顺序就不是最优的了,还是会有很多冗杂的操作

所以,最后的优化就是,在搜索过程中,用函数计算下一个要搜索的点(其实是启发式搜索的启发函数)。计算的标准就是,改点所在的行、列、九宫格内,还没有没使用的数字的数量,越少越好

(虽然一开始觉得这样很暴力,但是可以让搜索树变得超级小)

一开始T掉的点跑了大约6秒(手动测),优化之后变成717ms,时间限制是4s

ps:启发式搜索还是要选好启发函数

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int ans,cnt,sum;int ju[10][10],X[10][10],Y[10][10],S[10][10];bool vis[10][10],used[10][10];bool flg=0;struct hh{    int x,y;};int muti[10][10]={{0,0,0,0,0, 0,0,0,0,0},                  {0,6,6,6,6, 6,6,6,6,6},                  {0,6,7,7,7, 7,7,7,7,6},                  {0,6,7,8,8, 8,8,8,7,6},                  {0,6,7,8,9, 9,9,8,7,6},                  {0,6,7,8,9,10,9,8,7,6},                  {0,6,7,8,9, 9,9,8,7,6},                  {0,6,7,8,8, 8,8,8,7,6},                  {0,6,7,7,7, 7,7,7,7,6},                  {0,6,6,6,6, 6,6,6,6,6}};hh getit(){    hh ret;    int cm=15,sum=0;    for(int i=1;i<=9;++i)      for(int j=1;j<=9;++j)        if(!ju[i][j])        {            sum=0;            int wh=(i-1)/3*3+(j-1)/3+1;            for(int k=1;k<=9;++k)              if(!X[i][k]&&!Y[j][k]&&!S[wh][k])                sum++;            if(sum<cm)            {                cm=sum;                ret.x=i;                ret.y=j;            }        }    return ret;}void dfs(int x,int y,int k,int tot){    if(x>=1&&y<=9&&x<=9&&y>=1&&!vis[x][y]&&!used[x][y])    {        int wh=(x-1)/3*3+(y-1)/3+1;        for(int i=1;i<=9;++i)          if(!X[x][i]&&!Y[y][i]&&!S[wh][i])          {            X[x][i]=Y[y][i]=S[wh][i]=vis[x][y]=1;            ju[x][y]=i;             if(k==cnt) ans=max(ans,tot+i*muti[x][y]);            else            {                hh xx=getit();                dfs(xx.x,xx.y,k+1,tot+ju[x][y]*muti[x][y]);            }            ju[x][y]=0;            X[x][i]=Y[y][i]=S[wh][i]=vis[x][y]=0;          }    }}int main(){    for(int i=1;i<=9;++i)      for(int j=1;j<=9;++j)      {         scanf("%d",&ju[i][j]);         if(!ju[i][j])          {            cnt++;            continue;         }         sum+=ju[i][j]*muti[i][j];         used[i][j]=vis[i][j]=true;         int wh=(i-1)/3*3+(j-1)/3+1;         X[i][ju[i][j]]=S[wh][ju[i][j]]=Y[j][ju[i][j]]=1;      }    hh xx=getit();    dfs(xx.x,xx.y,1,sum);     if(ans==0) ans--;     printf("%d",ans);    return 0;}