传送门

这道题是很好的一道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. Netty和Akka有什么不同?

    摘要: Akka is a concurrency framework built around the notion of actors and composable futures, Akka w ...

  2. Windows下maven安装配置(包括本地化仓库配置)

    一.下载maven maven官网:http://maven.apache.org/ 下载下来也就是一个压缩文件,解压.我下载的是3.5.2版本,解压之后如下: 路径为 :D:\Program Fil ...

  3. [转]文件IO详解(二)---文件描述符(fd)和inode号的关系

    原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...

  4. nexus批量更新jar包

    nexus批量更新jar包 学习了:https://blog.csdn.net/newtelcom/article/details/54379607 手动进行jar包的拷贝,在维护界面内进行批量更新:

  5. memcache的学习路线图

     memcache学习材料 //memcache自带的github 上的 wiki     //席剑飞 Memcache(MC)系列 1~8系列 评注: memcache系统写的最深的一博客,建议一读 ...

  6. HTML--比较实用的小例子

    常用的前端实例: 1略 2.在网页商城中的图片当我们把鼠标放上去之后,图片会显示一个有颜色的外边框,图片某一部分的字体的颜色并发生改变 鼠标放上去之前 鼠标放上去之后: 实现的代码: <!DOC ...

  7. 子组件跟随父组件re-render

    想象一下这种场景,一个父组件下面一大堆子组件.然后呢,这个父组件re-render.是不是下面的子组件都得跟着re-render.可是很多子组件里面是冤枉的啊!!很多子组件的props 和 state ...

  8. C#语言循环语句for嵌套

  9. 【转载】回调函数(callback)是什么?

    一个很形象的例子: 你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货.在这个例子里,你的电话号码就叫回 ...

  10. freeIPMI README && issue about OpenIPMI kernel driver

    http://www.gnu.org/software/freeipmi/README FreeIPMI - Copyright (C) 2003-2013 FreeIPMI Core Team Fr ...