当前位置: 首页 > news >正文

DFS之剪枝与优化AcWing 166. 数独

DFS之剪枝与优化AcWing 166. 数独

原题链接

AcWing 166. 数独

算法标签

搜索 深度优先搜索 DFS

思路

优化搜索顺序: 从当前能填合法数字最少的位置开始填数字
排除等效冗余: 任意一个状态下,我们只需要找一个位置填数即可,而不是找所有的位置和可填的数字.
位运算:由于涉及大量check判定(即判断数字放在该行, 列, 九宫格),对check进行优化,
优化方式
对于每一行,每一列,每一个九宫格,利用一个九位二进制数保存,当前还有哪些数字可以填写.
lowbit: 取出当前可以能填的数字.

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
#define ump unordered_map
#define pq priority_queue
#define rep(i, a, b) for(int i=a;i<b;++i)
#define Rep(i, a, b) for(int i=a;i>b;--i)
using namespace std;
typedef pair<int, int> PII;
const int N=9, M=1<<N;
//ones表示0-2^9(二进制)里1的个数,mp找出该行哪一列可以填写数字,如mp[(10)2] = 1则第二列可以填1
int ones[M], mp[M];
//分别表示行,列,大方格中尚未填写的数字
int r[N], c[N], cell[3][3];
char str[86];
//int t, n, m, cnt, ans; 
inline int rd(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put(int x) {
    if(x<0) putchar('-'),x=-x;
    if(x>=10) put(x/10);
    putchar(x%10^48);
}
void init(){
	//初始状态9位二进制全是1 即所有位置可填写
    rep(i, 0, N){
        r[i]=c[i]=(1<<N)-1;
    }
    rep(i, 0, 3){
        rep(j, 0, 3){
            cell[i][j]=(1<<N)-1;
        }
    }
}
// is_set = true表示(x, y)填上t, 否则则把x,y处的数字删掉, t 是0-8
void draw(int x, int y, int t, bool is_set){
    if(is_set){
        str[x*N+y]='1'+t;
    }else{
        str[x*N+y]='.';
    }
    int v=1<<t;
    if(!is_set){
        v=-v;
    }
    //如果某位尚未选择,对应二进制位为1, 故应减v, 将1变为0
    //如果某位已选择,它的二进制为0,经上面取反,负负得正,将0变为1
    r[x]-=v;
    c[y]-=v;
    cell[x/3][y/3]-=v;
}
int lowbit(int x){
    return x&-x;
}
// 对于位于(x, y)的格子 合法数字选择
int get(int x, int y){
    return r[x]&c[y]&cell[x/3][y/3];
}
// cnt表示还剩余未填写格子数
bool dfs(int cnt){
    if(!cnt){
        return true;
    }
    // 最多可以填数字个数
    int minv=10;
    int x, y;
    rep(i, 0, N){
        rep(j, 0, N){
            if(str[i*N+j]=='.'){
             //可填的数字状态,如010001,是1则表示可以填
                int state=get(i, j);
                 //选择个数最少的1,使分支数量最少
                if(ones[state]<minv){
                    minv=ones[state];
                    x=i, y=j;
                }
            }
        }
    }
    int state=get(x, y);
    // 做lowbit操作,选择每个分支
    for(int i=state; i; i-=lowbit(i)){
     // t为填充的数字
        int t=mp[lowbit(i)];
        // 填充数字t
        draw(x, y, t, true);
        // 填充成功,则返回
        if(dfs(cnt-1)){
            return true;
        }
        // 失败回溯 
        draw(x, y, t, false);
    }
    return false;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	//打表,得知该位置可以填写哪一个数字
	rep(i, 0, N){
	    mp[1<<i]=i;
	}
	rep(i, 0, 1<<N){
	    rep(j, 0, N){
	        ones[i]+=i>>j&1;
	    }
	}
	while(scanf("%s", str), str[0]!='e'){
	    init();
	    int cnt=0;
	    for(int i=0, k=0; i<N; ++i){
	        for(int j=0; j<N; ++j, ++k){
            if(str[k]!='.'){
                int t=str[k]-'1';
                draw(i, j, t, true);
            }else{
                cnt++;
            }
	        }
	    }
	    dfs(cnt);
	    puts(str);
	}
	return 0;
}

参考文献
AcWing 166. 数独(算法提高课)y总讲解
AcWing 166. 数独题解

原创不易
转载请标明出处
如果对你有所帮助 别忘啦点赞支持哈
在这里插入图片描述

相关文章:

  • 公司保护知识产权做法有哪些
  • Map和mybatis
  • 信息化与工业化融合,MES管理系统助力制造业发展
  • 国稻种芯百团计划行动 邓兴旺:依靠中国农业现代化的实现
  • Promethues入门,看懂不会写
  • Windows 10硬盘数据怎么永久擦除?
  • Jenkins 踩坑(四)|基于接口自动化测试完成
  • package.json配置
  • [折腾]使用SSH服务实现一个socks5代理服务器
  • java计算机毕业设计我的大学电子相册源码+系统+数据库+lw文档+mybatis+运行部署
  • 中小型企业应如何选择OA管理系统
  • Kubernetes学习记录之(jenkins slave安装配置)
  • java计算机毕业设计文学阅读平台源码+系统+数据库+lw文档+mybatis+运行部署
  • windows下安装docker
  • 3D格式转换神器HOOPS Exchange使用教程(一):打印组件结构
  • 【译】JS基础算法脚本:字符串结尾
  • 【Leetcode】104. 二叉树的最大深度
  • Angular4 模板式表单用法以及验证
  • AWS实战 - 利用IAM对S3做访问控制
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • Hibernate【inverse和cascade属性】知识要点
  • Java IO学习笔记一
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • Laravel 菜鸟晋级之路
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • MySQL几个简单SQL的优化
  • Vue小说阅读器(仿追书神器)
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 关于Flux,Vuex,Redux的思考
  • 前端性能优化--懒加载和预加载
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 小程序测试方案初探
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • #NOIP 2014# day.1 T2 联合权值
  • #pragma 指令
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • (Matlab)使用竞争神经网络实现数据聚类
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • .Net core 6.0 升8.0
  • .NET Core Web APi类库如何内嵌运行?
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .net用HTML开发怎么调试,如何使用ASP.NET MVC在调试中查看控制器生成的html?
  • @configuration注解_2w字长文给你讲透了配置类为什么要添加 @Configuration注解
  • @GetMapping和@RequestMapping的区别
  • [ActionScript][AS3]小小笔记
  • [BZOJ 3282] Tree 【LCT】
  • [BZOJ4010]菜肴制作
  • [C语言]编译和链接
  • [EULAR文摘] 脊柱放射学持续进展是否显著影响关节功能
  • [hdu 2896] 病毒侵袭 [ac自动机][病毒特征码匹配]
  • [hibernate]基本值类型映射之日期类型
  • [HNOI2008]水平可见直线