问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22
==========================分割线==================================
 
这个题刚开始直接用bfs去做,但是开的标记数组的维数会非常高,后来才在网上看到用康拓展开,能用到康拓展开是因为这可以看成是一个序列,所以可以用康拓展开求出他在全排列中的次序,这样标记数组就可以开一维的了,这道题的广搜和三个水杯那个题差不多
代码如下:
 #include<iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
typedef long long LL;
struct Node{
int cur[];
LL step;
};
Node s, e;
const int N = 1e6;
const int Next[][] = {{, }, {, }, {-, }, {, -}};//搜索的四个方向
bool vis[N * ];//标记数组
int fac[] = {, , , , , , , , , };//前几个数的阶乘
LL cantor(int s[])//康拓展开
{
LL ans = ;
int n = ;
for (int i = ; i < n - ; i++)
{
int tmp = ;
for (int j = i + ; j < n; j++)
if (s[j] < s[i])
tmp++;
ans += fac[n - i - ] * tmp;
}
return ans;
}
void cantor_reverse(int index, int a[])//康拓展开逆, 在本道题中未使用
{
index--;
int n = ;
bool visit[];
memset(visit, false, sizeof(visit));
for (int i = ; i < n; i++)
{
int tmp = index / fac[n - i - ];
for (int j = ; j <= tmp; j++)
if (visit[j])
tmp++;
a[i] = tmp + ;
visit[tmp] = true;
index %= fac[n - i - ];
}
}
bool ischecked(int row, int col)//检查是否满足移动的条件
{
return (row > && col > && row < && col < );
}
bool matched(Node node)//看是否达到给定的状态
{
for (int i = ; i < ; i++)
if (node.cur[i] != e.cur[i])
return false;
return true;
}
LL bfs()
{
memset(vis, false, sizeof(vis));
queue<Node> Q;
s.step = ;
Q.push(s);
Node p, q;
int start_num = cantor(s.cur);
vis[start_num] = true;//标记第一个元素
while (!Q.empty())
{
p = Q.front();
Q.pop();
int pos;
for (pos = ; pos < ; pos++)
if (p.cur[pos] == )//将"."当成9来计算
break;
int row, col, new_row, new_col;
row = pos / + ;
col = pos % + ;
for (int i = ; i < ; i++)
{
new_row = row + Next[i][];
new_col = col + Next[i][];
if (ischecked(new_row, new_col))//判断是否满足可移动的条件
{
q = p;
q.step = p.step + ;
//下面三步是交换这两个数(也就是移动到空位去)
int t = q.cur[(row - ) * + col - ];
q.cur[(row - ) * + col - ] = q.cur[(new_row - ) * + new_col - ];
q.cur[(new_row - ) * + new_col - ] = t;
if (matched(q))//如果找到之后直接返回
{
return q.step;
}
int num = cantor(q.cur);
if (!vis[num])
{
vis[num] = true;
Q.push(q);
}
}
}
}
return -;//找不到就返回-1
}
int main()
{
char sta[], en[];
scanf("%s %s", sta, en);
for (int i = ; i < ; i++)
if (sta[i] != '.')
s.cur[i] = sta[i] - '';
else
s.cur[i] = ;//将'.'看成9
for (int i = ; i < ; i++)
if (en[i] != '.')
e.cur[i] = en[i] - '';
else
e.cur[i] = ;
LL tmp = bfs();
printf("%lld\n", tmp); return ;
}

九宫重拍(bfs + 康拓展开)的更多相关文章

  1. Eight (HDU - 1043|POJ - 1077)(A* | 双向bfs+康拓展开)

    The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've see ...

  2. bnuoj 1071 拼图++(BFS+康拓展开)

    http://www.bnuoj.com/bnuoj/problem_show.php?pid=1071 [题意]:经过四个点的顺逆时针旋转,得到最终拼图 [题解]:康拓展开+BFS,注意先预处理,得 ...

  3. hdu 1043 pku poj 1077 Eight (BFS + 康拓展开)

    http://acm.hdu.edu.cn/showproblem.php?pid=1043 http://poj.org/problem?id=1077 Eight Time Limit: 1000 ...

  4. 8数码,欺我太甚!<bfs+康拓展开>

    不多述,直接上代码,至于康拓展开,以前的文章里有 #include<iostream> #include<cstdio> #include<queue> using ...

  5. hdu-1043 bfs+康拓展开hash

    因为是计算还原成一种局面的最短步骤,应该想到从最终局面开始做bfs,把所有能到达的情况遍历一遍,把值存下来. bfs过程中,访问过的局面的记录是此题的关键,9*9的方格在计算过程中直接存储非常占内存. ...

  6. HDU 4531 bfs/康拓展开

    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=4531 吉哥系列故事——乾坤大挪移 Time Limit: 2000/1000 MS (Java/Othe ...

  7. 蓝桥杯 历届试题 九宫重排 (bfs+康托展开去重优化)

    Description 如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着.与空格子相邻的格子中的卡片可以移动到空格中.经过若干次移动,可以形成第二个图所示的局面. 我们把第一个图的 ...

  8. cdoj 414 八数码 (双向bfs+康拓展开,A*)

    一道关乎人生完整的问题. DBFS的优越:避免了结点膨胀太多. 假设一个状态结点可以扩展m个子结点,为了简单起见,假设每个结点的扩展都是相互独立的. 分析:起始状态结点数为1,每加深一层,结点数An ...

  9. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

随机推荐

  1. 【NOI2006】最大获利

    [问题描述] 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU 集团旗下的CS&T 通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就 ...

  2. DOM4J 读取XML配置文件进行数据库连接

        介绍介绍DOM4J.    据说是非常优秀非常优秀的Java XML  API(Dom4j is an easy to use, open source library for working ...

  3. 50个jQuery代码段帮你成为更好的JavaScript开发者

    1. 如何创建嵌套的过滤器: 允许你减少集合中的匹配元素的过滤器,只剩下那些与给定的选择器匹配的部分.在这种情况下,查询删除了任何没(:not)有(:has)包含class为“selected”(.s ...

  4. Bootstrap中的 Typeahead 组件

    Bootstrap 中的 Typeahead 组件其实就是嵌入到其中的typeahead.js插件,可以完成输入框的自动匹配功能,在通过一些人工的调整基本可以胜任所有的匹配功能和场景,下面介绍下简单的 ...

  5. jQuery实现按Enter键触发事件?

    按Enter触发 $(function(){ document.onkeydown = function(e){ var ev = document.all ? window.event : e; ) ...

  6. VISUAL STUDIO 2005连接MYSQL数据库

    // mysql.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <string.h> #include &l ...

  7. 清橙A1484

    http://www.tsinsen.com/ViewGProblem.page?gpid=A1484### 题解: 在线插入并不好做,我们将所有操作离线,变为删除操作. 每次询问的时候对于当前B串所 ...

  8. 随手写的Java向文本文件写字符串的类

    今天看了一篇讲Java IO流的文章,好长时间没用IO流了,回顾了一下Java编写IO程序的思路,之前文章中有介绍.对于写二进制文件我们习惯用 面向字节类的流.对于写字符我们使用面向字符类的流.但是我 ...

  9. Solr In Action 笔记(1) 之 Key Solr Concepts

    Solr In Action 笔记(1) 之 Key Solr Concepts 题记:看了下<Solr In Action>还是收益良多的,只是奈何没有中文版,只能查看英语原版有点类,第 ...

  10. CSS3自定义图标

    http://ntesmailfetc.blog.163.com/blog/static/206287061201292631536545/ http://www.zhihu.com/question ...