洛谷P1074:靶形数独(搜索、剪枝)

解析

搜索题都是玄学

本题暴搜人人都会写,关键是如何剪枝
我一直在最优性剪枝上纠结qwq
但仔细想想,不同方案的权值差别没有那么大
再加上剪枝时不可避免的要放弃一些准确度
所以最优性剪枝在本题可能确实没有太大的作用

考虑我们平时如何玩数独
肯定是先从东西少的地方开始搜啦!
然后放到代码上试试…
诶?怎么切了?

我们理性的分析一下
可能有一些各自由于自己行已经填的东西所以几乎已经确定了
然而如果先搜其他行可能会在一个与本来可以确定的地方矛盾的搜索树上走的太深
所以我们先确定能确定的再搞剩下的会大大加速

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(a,b) fprintf(stderr,a,b)
const int N=1e5+100;
const int M=2e5+100;
const int mod=998244353;
const double eps=1e-8;
inline ll read(){
  ll x=0,f=1;char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}
int a[11][11] = {
	{0,0,0,0,0,0,0,0,0,0,0},
	{0,6,6,6,6,6,6,6,6,6,0},
	{0,6,7,7,7,7,7,7,7,6,0},
	{0,6,7,8,8,8,8,8,7,6,0},
	{0,6,7,8,9,9,9,8,7,6,0},
	{0,6,7,8,9,10,9,8,7,6,0},
	{0,6,7,8,9,9,9,8,7,6,0},
	{0,6,7,8,8,8,8,8,7,6,0},
	{0,6,7,7,7,7,7,7,7,6,0},
	{0,6,6,6,6,6,6,6,6,6,0},
	{0,0,0,0,0,0,0,0,0,0,0}
};
bool hang[10][10],lie[10][10],d[10][10],num[10];
int mp[10][10],tot;
#define bel(a,b) ((a-1)/3*3+(b-1)/3+1)
int now,ans;
struct node{
  int x,num;
}p[10];
bool cmp(node a,node b){return a.num>b.num;}
int id[10][10],cnt[10];
void dfs(int k,int x,int o){
  if(k>9){
    ans=max(ans,now);return;
  }
  if(o>cnt[x]){
    dfs(k+1,p[k+1].x,1);
    return;
  }
  int y=id[x][o];
  for(int i=1;i<=9;i++){
    if(hang[x][i]||lie[y][i]||d[bel(x,y)][i]) continue;
    hang[x][i]=lie[y][i]=d[bel(x,y)][i]=1;
    now+=i*a[x][y];
    dfs(k,x,o+1);
    hang[x][i]=lie[y][i]=d[bel(x,y)][i]=0;
    now-=i*a[x][y];
  }
  return;
}
int main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  //start=clock();
  for(int i=1;i<=9;i++){
    p[i].x=i;
    for(int j=1;j<=9;j++){
      int o=read();mp[i][j]=o;
      if(o){
	hang[i][o]=lie[j][o]=d[bel(i,j)][o]=1;
	now+=o*a[i][j];
	p[i].num++;	
      }
      else id[i][++cnt[i]]=j;
    }
  }
  sort(p+1,p+1+9,cmp);
  dfs(1,p[1].x,1);
  printf("%d\n",ans?ans:-1);
  return 0;
}
//2025

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值