传送门

这道题是很好的一道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. 什么是 Linux

    什么是Linux Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程序和网络 ...

  2. BZOJ——2096: [Poi2010]Pilots

    http://www.lydsy.com/JudgeOnline/problem.php?id=2096 Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: ...

  3. linux 系统命令----修改主机名

    1. hostname    ***** 2.修改/etc/sysconfig/network 3./etc/hosts 最后第三步没有必要!

  4. 取汉子拼音首字母的VB.Net方法

    '/ <summary> '/ 获得一个字符串的汉语拼音码 '/ </summary> '/ <param name="strText">字符串 ...

  5. SolidEdge如何打开或关闭自动标注尺寸

    工具-聪慧-自动标注尺寸                    

  6. cocos2dx3.0 2048多功能版

    1.2048项目描写叙述 1.1.2048功能描写叙述 实现手机上2048的功能,同一时候具备能够删除随意一个方块的功能,悔棋功能,退出自己主动保存,启动自己主动载入功能. 1.2.2048所需技术 ...

  7. Android中怎样自己制作su

    本文原博客:http://hubingforever.blog.163.com/blog/static/171040579201372915716149/ 在Android源代码的system\ext ...

  8. YII 多子域名同步登录

    a.meylou.com和b.meylou.com不做登录.c.meylou.com这个专门做用户登录.c站登录之后a,b站点同时登录. 第一步:修改php.ini配置文件,把cookie_domai ...

  9. kafka 和 zookeeper 常用命令记录

    启动zookeeper zkServer.sh start 启动kafka服务器 kafka-server-start.sh /software/kafka_2.10-0.10.2.1/config/ ...

  10. LCS的几种求法

    \(LCS:\) 对于两个长度均为 \(N\) 的数列 \(A\) 和 \(B\) ,存在一个数列 \(C\) 使得 \(C\) 既是 \(A\) 的子序列有事 \(B\) 的子序列,现在需要求这个数 ...