codevs 1174 靶形数独 (启发式搜索)

*PS:卡常什么的最讨厌了

go to the problem

因为题面太长所以并不想粘qwq

第一遍打的暴搜,codevs 上90,洛谷75,感觉自己萌萌的。

结果打完启发函数后,codevs上A了,洛谷上一直T掉一个点QAQ,优化了一晚上,还是T掉(而且这个点暴搜没T),最后放弃了… T _ T

方法就是每次都从可能性最小的点开始搜,记一下每行每列每宫里已经填了的数的种类,从种类最多的开始搜(也可以加上已经填了的数量)。同时记得打表(分数,宫也可以)。

当然你也可以考虑每次从0最少的地方开始搜,或者进行最优化剪枝(当前还没填的数的个数*90+当前得分<=ans return)、或者用inline、register或O2优化、加上位运算或手读、从9到1倒着枚举、能用char的用char…

暴搜

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;

int cnt,ans=-1,Sum;
int a[10][10],hang[10][10],lie[10][10],gong[10][10][10];
int ch[10],cl[10],cg[10][10];
struct maple{
    int x,y,h;
}point[100];
int score[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}};                  

bool cmp(maple a,maple b)
{
    return a.h>b.h;
}
void Done_used(int i,int j,int k,int d,int d2)
{
    hang[i][k]=lie[j][k]=gong[(i-1)/3][(j-1)/3][k]=d;
}
void Dfs(int k,int sum)  //填到第k个数,总值为sum  
{
    if(k==cnt)
    {
        ans=max(ans,sum);
        return ;    
    }
    int x=point[k+1].x,y=point[k+1].y;
    for(int i=1;i<=9;++i)
       if(!hang[x][i]&&!lie[y][i]&&!gong[(x-1)/3][(y-1)/3][i])
       {
              Done_used(x,y,i,1,1);
              Dfs(k+1,sum+i*score[x][y]);
              Done_used(x,y,i,0,-1);
       }
}
int main()
{

    for(int i=1;i<=9;++i)
       for(int j=1;j<=9;++j)
       {
           scanf("%d",&a[i][j]);
           Done_used(i,j,a[i][j],1,1); 
           Sum+=a[i][j]*score[i][j];
       }
    for(int i=1;i<=9;++i)
       for(int j=1;j<=9;++j)
          if(!a[i][j])
                point[++cnt]=(maple){i,j,0};
    Dfs(0,Sum); 
    printf("%d",ans);
    return 0;
}

codevs AC

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;

int cnt,ans=-1,Sum;
int a[10][10],hang[10][10],lie[10][10],gong[10][10][10];
struct maple{
    int x,y;
}point[100];
int score[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}}; 

void Done_used(int i,int j,int k,int d,int l,int r)
{
    hang[i][k]=lie[j][k]=gong[l][r][k]=d;
}
int Done_data()
{
    int sum=0,pos;
    for(int i=1;i<=cnt;++i)
       if(!a[point[i].x][point[i].y])
       {
           int k=0,l=(point[i].x-1)/3,r=(point[i].y-1)/3;
           for(int j=1;j<=9;++j)
              if(hang[point[i].x][j]||lie[point[i].y][j]||gong[l][r][j])
                  ++k;
           if(k>sum)
           {
               sum=k;
               pos=i;
           }
       }
    return pos;
}
void Dfs(int k,int sum)  // 填到第k个数,总值为sum  
{
    if(k==cnt)
    {
        ans=max(ans,sum);
        return ;    
    }
    if(sum+(cnt-k)*90<=ans) return;
    int j=Done_data();
    int x=point[j].x,y=point[j].y;
    int l=(x-1)/3,r=(y-1)/3;
    for(int i=1;i<=9;++i)
       if(!hang[x][i]&&!lie[y][i]&&!gong[l][r][i])
       {
           a[x][y]=i;
           Done_used(x,y,i,1,l,r);
           Dfs(k+1,sum+i*score[x][y]);
           Done_used(x,y,i,0,l,r);
           a[x][y]=0;
       }
}
int main()
{

    for(int i=1;i<=9;++i)
       for(int j=1;j<=9;++j)
       {
           scanf("%d",&a[i][j]);
           Sum+=a[i][j]*score[i][j];
           if(!a[i][j])  point[++cnt]=(maple){i,j};
           else  Done_used(i,j,a[i][j],1,(i-1)/3,(j-1)/3); 
       }
    Dfs(0,Sum); 
    printf("%d",ans);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值