原题https://uva.onlinejudge.org/external/13/1343.pdf


题意:  

有个#字型的棋盘,2行2列,一共24个格。

如图:每个格子是1或2或3,一共8个1,8个2,8个3.

有A~H一共8种合法操作,比如A代表把A这一列向上移动一个,最上面的格会补到最下面。

求:使中心8个格子数字一致的最少步骤,要输出具体的操作步骤及最终中心区域的数字。如果有多个解,输出字典序最小的操作步骤。


分析:

很明显的一个状态空间搜索问题,不过可以注意到,虽然每一个状态有八个可能的后续状态,随着操作数n的增加,总状态数 8^n 还是大得可怕。比如当n=11时,总状态为8^11 = 85亿。就算通过自己创建特制的哈希表进行状态判重,优化效果并不明显,因为最近一直在做状态空间搜索问题,即使用bfs+剪枝+哈希表,这些程序都无一例外的超时了,所以现在看到状态空间搜索问题,如果没有特别好的剪枝,我绝对不敢用bfs了.....

回到这道题,所有可以用bfs,回溯解决的问题,尤其是解答树的结点数没有明显上限的题,选择用迭代加深搜索算法都特别好用(原因可以参考我上一篇文章)。这里IDA*(迭代加深A*算法)其实说白了就是迭代加深+剪枝.

A*算法是对于每一步考虑 g(n) + h()和MAXD的关系。

稍微解释一下,g(n)是从起点到当前状态的总步数,MAXD是我们提前通过计算证明得到的最短路线总步数的上限,h()是启发函数,是整个算法的关键,我们设计的h()可以预估从当前状态到目标状态至少需要的步数。

这样,上面的关系式就很好理解了。g(n) + h() > MAXD 意味着当前已经走的步数+至少还需要的步数 > 我可以走的步数上限,这种状态,必然已经没有继续的必要,回溯。

对于这道题,可以注意到,对于每一次操作,我们最多可以让中心格子多一个目标数字,如果当前中心格子待整理的数字个数大于我们还可以走的步数,回溯。

这样,就得到了

    if (d + num_unordered() > MAXD) return false;

    这一核心剪枝公式。 剩下的就简单了。

代码只有52行,还是很简洁的。而且运行速度很快。过30组数据只用了126ms.

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = , LEN = ;
int board[LEN][LEN - ] = { {, , , , , , }, {, , , , , , },
{, , , , , , }, {, , , , , , },
{, , , , , , }, {, , , , , , },
{, , , , , , }, {, , , , , , } };
int check_order[] = {, , , , , , , }, a[MAXN], maxd;
char order[]; int unordered() {
int n1 = , n2 = , n3 = ;
for (int i = ; i < LEN; i++)
if (a[check_order[i]] == ) n1++;
else if (a[check_order[i]] == ) n2++;
else n3++;
return LEN - max(max(n1, n2), n3);
} void rotate(int di) {
int t = a[board[di][]];
for (int i = ; i < LEN - ; i++) a[board[di][i - ]] = a[board[di][i]];
a[board[di][LEN - ]] = t;
} bool dfs(int d) {
int cnt = unordered();
if (!cnt) return true;
if (cnt + d > maxd) return false;
int temp[MAXN]; memcpy(temp, a, sizeof(a));
for (int i = ; i < LEN; i++) {
rotate(i);
order[d] = i + 'A';
if (dfs(d + )) return true;
memcpy(a, temp, sizeof(a));
}
return false;
} int main() {
freopen("in", "r", stdin);
while (scanf("%d", &a[]) && a[]) {
for (int i = ; i < MAXN; i++) scanf("%d", &a[i]);
if (!unordered()) { printf("No moves needed\n%d\n", a[]); continue;}
for (maxd = ;; maxd++) if (dfs()) break;
for (int i = ; i < maxd; i++) printf("%c", order[i]);
printf("\n%d\n", a[]);
}
return ;
}

顺便纪念一下排第六(前面3个是virtual oj......)

Uva1343-The Rotation Game-IDA*算法的更多相关文章

  1. HUD 1043 Eight 八数码问题 A*算法 1667 The Rotation Game IDA*算法

    先是这周是搜索的题,网站:http://acm.hdu.edu.cn/webcontest/contest_show.php?cid=6041 主要内容是BFS,A*,IDA*,还有一道K短路的,.. ...

  2. 【学时总结】 ◆学时·II◆ IDA*算法

    [学时·II] IDA*算法 ■基本策略■ 如果状态数量太多了,优先队列也难以承受:不妨再回头看DFS-- A*算法是BFS的升级,那么IDA*算法是对A*算法的再优化,同时也是对迭代加深搜索(IDF ...

  3. HDU3567 Eight II —— IDA*算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3567 Eight II Time Limit: 4000/2000 MS (Java/Others)  ...

  4. The Rotation Game(IDA*算法)

    The Rotation Game Time Limit : 30000/15000ms (Java/Other)   Memory Limit : 300000/150000K (Java/Othe ...

  5. UVA-1343 The Rotation Game (IDA*)

    题目大意:数字1,2,3都有八个,求出最少的旋转次数使得图形中间八个数相同.旋转规则:对于每一长行或每一长列,每次旋转就是将数据向头的位置移动一位,头上的数放置到尾部.若次数相同,则找出字典序最小旋转 ...

  6. [poj2286]The Rotation Game (IDA*)

    //第一次在新博客里发文章好紧张怎么办 //MD巨神早已在一个小时前做完了 The Rotation Game Time Limit: 15000MS Memory Limit: 150000K To ...

  7. 7-12 The Rotation Game IDA*

    状态搜索题目  一开始打算用bfs  但是图给的不是矩形图  有点难以下手 参考了 lrj    将图上所有的点进行标号  直接一个一维数组就解决了图的问题  并且明确了每个点的标号  处理起来十分方 ...

  8. POJ2286 The Rotation Game[IDA*迭代加深搜索]

    The Rotation Game Time Limit: 15000MS   Memory Limit: 150000K Total Submissions: 6325   Accepted: 21 ...

  9. 八数码(IDA*算法)

    八数码 IDA*就是迭代加深和A*估价的结合 在迭代加深的过程中,用估计函数剪枝优化 并以比较优秀的顺序进行扩展,保证最早搜到最优解 需要空间比较小,有时跑得比A*还要快 #include<io ...

  10. HDU1560 DNA sequence —— IDA*算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1560 DNA sequence Time Limit: 15000/5000 MS (Java/Oth ...

随机推荐

  1. 关于SQL IO的一些资料

      前些天在做优化的时候发现一个有意思的现象,单纯的SQL执行很快,秒级返回,但是页面响应却很慢,一直在想这是为什么呢?有点怀疑服务器的IO有问题,想了想做了个实验,模拟了同样的场景,通过优化SQL将 ...

  2. framework not found -fno-arc编译错误

    由于我是刚接手的代码  然后我拿来运行根本就是运行不了的  然后需要在linker 那边删除点东西就可以了. 把下边的两个删除就可以了 关于other linker flags 的介绍 请参考http ...

  3. Bridge 模式

    Bridge 模式将抽象和行为划分开来,各自独立,但能动态的结合.在面向对象设计的基本概念中,对象这个概念实际是由属性和行为两个部分组成的,属性我们可以认为是一种静止的,是一种抽象,一般情况下,行为是 ...

  4. 【HDU3487】【splay分裂合并】Play with Chain

    Problem Description YaoYao is fond of playing his chains. He has a chain containing n diamonds on it ...

  5. Oracle数据库之视图与索引

    Oracle数据库之视图与索引 1. 视图简介 视图是基于一个表或多个表或视图的逻辑表,本身不包含数据,通过它可以对表里面的数据进行查询和修改. 视图基于的表称为基表,视图是存储在数据字典里的一条SE ...

  6. DB2JAVIT:RC=9505解决方案

    DB2JAVIT:RC=9505解决方案 题记:WIN7下装DB2,启动任务中心.控制中心报DB2JAVIT:RC=9505. 解决方案:进入(计算机—>管理—>本地用户和组)把用户加入到 ...

  7. PHP框架_ThinkPHP数据库

    目录 1.ThinkPHP数据库配置 2.ThinkPHP数据库实例化模型 3.ThinkPHP数据库CURD操作 4.ThinkPHP数据库连贯操作 1.ThinkPHP数据库配置 App/Conf ...

  8. Linux操作:

    1.在Linux中第一个字符代表这个文件是目录.文件或链接文件等等. 当为[ d ]则是目录,当为[ - ]则是文件,若是[ l ]则表示为链接文档(link file),若是[ b ]则表示为装置文 ...

  9. YII 集成jquery

  10. 使用C语言获取当前系统的时间

    要想使用C语言来获取当前系统的时间,办法如下: 需要提前准备的工作: #include <stdio.h> #include <time.h> #include <std ...