传送门

这道题是很好的一道IDA*练习题。

首先我们先确定搜索的框架,我们要求的是用最少的修改次数使得所有的行,列,宫之内都有偶数个1,最直观的想法显然是先预处理出有奇数个1的行,列,宫,之后枚举每一个点,如果这个点在奇数个1的行/列/宫之中就开始修改,继续搜索。修改整个数独之后判定,回溯。

这个正确性是没问题的,但是你难以通过有效的手段减少搜索树大小(比如从1多的开始搜?),这样肯定会超时(想想靶型数独)。

于是我们引入新的操作:ID(迭代加深)搜索!

ID的原理是,有可能搜索树某些分枝非常的深,但里面并没有你要的解,如果你率先进入的话,就会浪费大量的时间在里面。有可能解的深度并不是很大,所以我们可以每次设定一个搜索的深度,如果超过这个深度就返回,之后继续加大深度搜索,所以叫迭代加深。

但是这样我们依然可能很慢,所以我们再加上一个,A*算法!

A*算法简单来说,就是设计一个估价函数,估计未来的搜索情况,选择当前估计最好的一个搜索方向去搜索。估计的值越接近实际值,搜索效率越高。估价函数有一个原则,就是估计的值不可以大于实际值,否则就会导致得到错误的答案。(因为估计值过大掩盖了真实的解)而且我们无需担心正确性,因为A*算法只是优先进入分支,在进行一段时间搜索之后,原来被忽略的分支又将进入计算。A*的估价函数如果一直是0,那么他就相当于是一个无优化的搜索,所以说A*算法的效率一般来讲是高于普通搜索的,至于高多少就要看设计的估价函数的高明之处了。

A*的实现比较复杂,但与ID结合起来成为IDA*就比较好实现了,它其实可以被视为剪枝,当当前的值加上估价值比当前的最大深度更大,就直接返回,相当于剪枝了。在这道题中,我们要做的就是从小到大枚举搜索深度(就是修改的次数),在每次设计一个估价函数,根据上面的原则,我们修改之后,至多需要max有奇数个1的(行,列,宫)次修改,每次估价函数设为三者最大值即可。

这样搜索快到飞起,也有可能是本题数据比较水……

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n') using namespace std;
typedef long long ll;
const int M = ;
const int INF = ; int read()
{
int ans = ,op = ;
char ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-') op = -;
ch = getchar();
}
while(ch >= '' && ch <= '')
{
ans *= ;
ans += ch - '';
ch = getchar();
}
return ans * op;
} int b,c,r,row[],col[],blo[],maxd;
char s[]; int B(int x,int y)
{
return ((x - ) / * + (y - ) / ) + ;
} int h()
{
return max(r,max(b,c));
} int cal(int x)
{
return (!x) ? - : ;
} void change(int i,int j)
{
row[i] ^= ,col[j] ^= ,blo[B(i,j)] ^= ;
r += cal(row[i]),c += cal(col[j]),b += cal(blo[B(i,j)]);
} void dfs(int x,int y,int d)
{
if(d > maxd) return;
if(x == && y == )
{
rep(i,,) if(row[i] | col[i] | blo[i]) return;
printf("%d\n",maxd),exit();
}
if(row[x] | col[y] | blo[B(x,y)])
{
change(x,y);
if(d + + h() <= maxd) (y == ) ? dfs(x+,,d+) : dfs(x,y+,d+);
change(x,y);
if(d + h() <= maxd) (y == ) ? dfs(x+,,d) : dfs(x,y+,d);
}
else (y == ) ? dfs(x+,,d) : dfs(x,y+,d);
} int main()
{
rep(i,,)
{
scanf("%s",s+);
rep(j,,) if(s[j] == '') change(i,j);
}
for(maxd = ;;maxd++) dfs(,,);
return ;
}

[USACO11NOV]二进制数独Binary Sudoku的更多相关文章

  1. P3032 [USACO11NOV]二进制数独Binary Sudoku

    题目描述 Farmer John's cows like to play an interesting variant of the popular game of "Sudoku" ...

  2. 2016年11月3日JS脚本简介数据类型: 1.整型:int 2.小数类型: float(单精度) double(双精度) decimal () 3.字符类型: chr 4.字符串类型:sting 5.日期时间:datetime 6.布尔型数据:bool 7.对象类型:object 8.二进制:binary 语言类型: 1.强类型语言:c++ c c# java 2.弱类型语

    数据类型: 1.整型:int 2.小数类型: float(单精度) double(双精度) decimal () 3.字符类型: chr 4.字符串类型:sting 5.日期时间:datetime 6 ...

  3. MySQL 二进制日志(Binary Log)

    同大多数关系型数据库一样,日志文件是MySQL数据库的重要组成部分. MySQL有几种不同的日志文件.通常包括错误日志文件,二进制日志,通用日志,慢查询日志,等等.这些日志能够帮助我们定位mysqld ...

  4. [逆向工程] 二进制拆弹Binary Bombs 快乐拆弹 详解

    二进制拆弹 binary bombs 教你最快速解题,成功拆弹 最近计算机基础课,的实验lab2,二进制拆弹,可以说是拆的我很快乐了(sub n, %hair) 此处头发减n 我刚开始做的时候很是懵逼 ...

  5. Leetcode之回溯法专题-37. 解数独(Sudoku Solver)

    Leetcode之回溯法专题-37. 解数独(Sudoku Solver) 编写一个程序,通过已填充的空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次.数字 1 ...

  6. 二进制日志BINARY LOG清理

    mysql> show master logs; +------------------+-----------+ | Log_name | File_size | +------------- ...

  7. Arduino 串口篇 Arduino发送二进制 send binary via RS232-to-USB to PC

    有用的链接在这里:http://hi.baidu.com/mizuda/item/06b7fdc1d0e45a0ec710b2dd 更加详细的内容请查阅Arduino官方:http://arduino ...

  8. 求解数独难题, Sudoku问题(回溯)

    Introduction : 标准的数独游戏是在一个 9 X 9 的棋盘上填写 1 – 9 这 9 个数字,规则是这样的: 棋盘分成上图所示的 9 个区域(不同颜色做背景标出,每个区域是 3 X 3 ...

  9. [Swift]LeetCode36. 有效的数独 | Valid Sudoku

    Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to th ...

随机推荐

  1. route命令走一波

    1.写文章去了解某个命令完全是兴起,并没有下定决心去学哪一套课程,目前的状态仍然是犹豫中,废话不多说进入正文,九月二十七这天看到了route命令,发现对路由这个命令很陌生,陌生到根本不知道它是用来干什 ...

  2. Spring的IoC容器-Spring BeanFactory容器

    虽然这个方法已经在3.1之后已经弃用了,但是可以了解一下. 在Spring中,有大量对BeanFactory接口的实现.其中,最常被使用的是XmlBeanFactory类.这个容器从一个XML文件中读 ...

  3. mysql获取子父级节点

    获取所有子节点 DROP FUNCTION IF EXISTS `F_Co29_GetAllChildrenIdsOfTaskevent`;DELIMITER //CREATE FUNCTION `F ...

  4. oracle存储过程中使用字符串拼接

    1.使用拼接符号“||” v_sql := 'SELECT * FROM UserInfo WHERE ISDELETED = 0 AND ACCOUNT =''' || vAccount || '' ...

  5. JSONKit升级XCODE后报一堆警告解决办法

    虽然我已经该用apple自己的json解析了,但是对于需要兼容低版本的,还是需要用第三方的, 目前用的最多的就有JSONKit了,包括微博sdk,但是一编译报一堆警告,看着很不爽.可以自己手动一个个修 ...

  6. 改动C:\WINDOWS\system32\drivers\etc\hosts 文件有什么作用

    host是一个没有扩展名的系统文件,能够用记事本等工具打开,其作用就是将一些常常使用的网址域名与其相应的IP地址建立一个关联"数据库".当用户在浏览器中输入一个须要登录的网址时,系 ...

  7. PHP网站渗透中的奇技淫巧:检查相等时的漏洞

    PHP是现在网站中最为常用的后端语言之一,是一种类型系统 动态.弱类型的面向对象式编程语言.可以嵌入HTML文本中,是目前最流行的web后端语言之一,并且可以和Web Server 如apache和n ...

  8. FastDFS的配置、部署与API使用解读(1)Get Started with FastDFS(转)

    转载请注明来自:诗商·柳惊鸿CSDN博客,原文链接:FastDFS的配置.部署与API使用解读(1)入门使用教程 1.背景 FastDFS是一款开源的.分布式文件系统(Distributed File ...

  9. jsp学习笔记总结

    Cookie中对保存对象的大小是有限制的 解决cookie中无法保存中文的问题: request.setCharacterEncoding URLEncoder.encode()编码 URLDecod ...

  10. CSDN-markdown编辑器之从线上导入Markdown文件

      CSDN-markdown编辑器支持从线上导入Markdown文件的功能,假设你用其他支持Markdown的编辑器在网上写了博客文章或说明档,想公布到CSDN博客中,就能够使用本功能非常方便的完毕 ...