hdu1043 经典的八数码问题 逆向bfs打表 + 逆序数
题意: 题意就是八数码,给了一个3 * 3 的矩阵,上面有八个数字,有一个位置是空的,每次空的位置可以和他相邻的数字换位置,给你一些起始状态 ,给了一个最终状态,让你输出怎么变换才能达到目的.
思路: 首先我们先判断一下可不可以达到最终目的,方法是根据逆序数,只要终止状态和起始状态的逆序数(空的位置不算)奇偶性相同就能,否则不能;
证明 :
加入当前空的位置是i,针对3 * 3 的也就是八数码问题(可能有别的数码,根据奇偶性答案不同) 如果向前或向后移动的话 当前的逆序数不变,如果像上移动的话有三种情况, 移动过来的这个数比那两个数都大,逆序数 - 2 ,移动过来的这个数比那两个数都小 逆序数 + 2,比一个大,比另一个小,逆序数 + 1 - 1 不变,所以怎么移动逆序数奇偶性不变,所以只有起始状态可终止状态逆序数奇偶性相同才能转换..
解决了判断,剩下的就是输出方法了,直接暴搜会TLE出"翔"来(测试数据太多),我们观察会发现,题目最终的目的地是同一个状态,无论什么最后都要到题目中给的那个终点,那么我们可以直接以终点为起点,遍历一边所有状态,然后把它存起来,等问的时候我们只要把存的方法变换一下就ok了,首先把整个序列颠倒过来,因为我们是反向打表,然后相应的 上 变 下 下 变 上 ... 因为是反向搜索..然后输出来就ok了, 这让我想起了以前做过的一道最短路,一群牛去一个地方开会,在回来问所有路径的最短和,路是单向的,我们只要直接以开会点为起点,跑两边最短路就ok了..想法是一样的.上代码.
//逆向BFS打表 AC
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<map>
#include<queue>
using namespace std;
typedef struct
{
int now_map[10];
string root;
int id0;
}NODE;
map<int ,string>ans_map;
map<int ,int>mk;
NODE xin ,tou;
char ans[800000];
int end_map[10] = {0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,0};
bool hash(int now[] ,string root)
{
int sum = 0 ,e = 1;
for(int i = 1 ;i <= 9 ;i ++)
{
sum += e * now[i];
e *= 10;
}
if(mk[sum])
return 1;
mk[sum] = 1;
ans_map[sum] = root;
return 0;
}
void DB_BFS()
{
for(int i = 1 ;i <= 9 ;i ++)
xin.now_map[i] = end_map[i];
xin.root = "";
xin.id0 = 9;
queue<NODE>q;
q.push(xin);
ans_map.clear();
mk.clear();
hash(xin.now_map ,"ud");
while(!q.empty())
{
tou = q.front();
q.pop();
if(tou.id0 >= 4)
{
xin = tou;
xin.root = tou.root + 'u';
xin.now_map[xin.id0] = tou.now_map[xin.id0-3];
xin.now_map[xin.id0-3] = 0;
xin.id0 -= 3;
if(!hash(xin.now_map ,xin.root))
{
q.push(xin);
}
}
if(tou.id0 <= 6)
{
xin = tou;
xin.root = tou.root + 'd';
xin.now_map[xin.id0] = tou.now_map[xin.id0+3];
xin.now_map[xin.id0+3] = 0;
xin.id0 += 3;
if(!hash(xin.now_map ,xin.root))
{
q.push(xin);
}
}
if(tou.id0 != 1 && tou.id0 != 4 && tou.id0 != 7)
{
xin = tou;
xin.root = tou.root + 'l';
xin.now_map[xin.id0] = tou.now_map[xin.id0-1];
xin.now_map[xin.id0-1] = 0;
xin.id0 --;
if(!hash(xin.now_map ,xin.root))
{
q.push(xin);
}
}
if(tou.id0 != 3 && tou.id0 != 6 && tou.id0 != 9)
{
xin = tou;
xin.root = tou.root + 'r';
xin.now_map[xin.id0] = tou.now_map[xin.id0+1];
xin.now_map[xin.id0+1] = 0;
xin.id0 ++;
if(!hash(xin.now_map ,xin.root))
{
q.push(xin);
}
}
}
}
int main ()
{
int i ,id0;
char str[5];
DB_BFS();
NODE A;
while(~scanf("%s" ,str))
{
if(str[0] == 'x')
{
A.id0 = 1;
A.now_map[1] = 0;
}
else
A.now_map[1] = str[0] - 48;
for(i = 2 ;i <= 9 ;i ++)
{
scanf("%s" ,str);
if(str[0] == 'x')
{
A.id0 = i;
A.now_map[i] = 0;
}
else
A.now_map[i] = str[0] - 48;
}
int sum = 0;
int ss = 0 ,e = 1;
for(i = 1 ;i <= 9 ;i ++)
{
ss += A.now_map[i] * e;
e *= 10;
if(!A.now_map[i])continue;
for(int j = 1 ;j < i ;j ++)
if(A.now_map[i] < A.now_map[j])
sum ++;
}
if(sum % 2)
{
printf("unsolvable\n");
continue;
}
int l = ans_map[ss].length();
for(i = 0 ;i < l ;i ++)
{
char c = ans_map[ss][l-i-1];
if(c == 'u')
ans[i] = 'd';
if(c == 'd')
ans[i] = 'u';
if(c == 'l')
ans[i] = 'r';
if(c == 'r')
ans[i] = 'l';
}
ans[l] = '\0';
puts(ans);
}
return 0;
}
hdu1043 经典的八数码问题 逆向bfs打表 + 逆序数的更多相关文章
- HDU1043 Eight(八数码:逆向BFS打表+康托展开)题解
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- poj 1077-Eight(八数码+逆向bfs打表)
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've see ...
- 【双向广搜+逆序数优化】【HDU1043】【八数码】
HDU上的八数码 数据强的一B 首先:双向广搜 先处理正向搜索,再处理反向搜索,直至中途相遇 visit 和 队列都是独立的. 可以用一个过程来完成这2个操作,减少代码量.(一般还要个深度数组) 优化 ...
- Eight(经典题,八数码)
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- HDOJ-1043 Eight(八数码问题+双向bfs+高效记录路径+康拓展开)
bfs搜索加记录路径 HDOJ-1043 主要思路就是使用双向广度优先搜索,找最短路径.然后记录路径,找到结果是打印出来. 使用康拓序列来来实现状态的映射. 打印路径推荐使用vector最后需要使用a ...
- hdu1043Eight (经典的八数码)(康托展开+BFS)
建议先学会用康托展开:http://blog.csdn.net/u010372095/article/details/9904497 Problem Description The 15-puzzle ...
- HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】
本题有写法好几个写法,但主要思路是BFS: No.1 采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重.如果只进行单向会超时. No.2 采用hash进行判重,宽搜采用单向就可以AC. No.3 ...
- 【洛谷】P1379 八数码难题(bfs)
题目 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局 ...
- hdu 1043 Eight (八数码问题)【BFS】+【康拓展开】
<题目链接> 题目大意:给出一个3×3的矩阵(包含1-8数字和一个字母x),经过一些移动格子上的数后得到连续的1-8,最后一格是x,要求最小移动步数. 解题分析:本题用BFS来寻找路径,为 ...
随机推荐
- 翻译:《实用的Python编程》03_03_Error_checking
目录 | 上一节 (3.2 深入函数) | 下一节 (3.4 模块) 3.3 错误检查 虽然前面已经介绍了异常,但本节补充一些有关错误检查和异常处理的其它细节. 程序是如何运行失败的 Python 不 ...
- 【产品设计】linux产品设计总结笔记
Linux 预研产品设计 产品的目的: 1.综合集团内部重复性开发的工作,将多种操作系统统一到科东统一负责 2.明确技术在哪些设备上是可行的,再去拓展.一开始不做平台化产品 3.软件规划需要结合硬 ...
- Linux速通03 目录文件的浏览、管理和维护
Linux文件系统的层次结构 # 树状结构:在Linux或Unix操作系统中,所有的文件和目录都被组织成一个以根节点开始的倒置的树状结构. # 目录的定义:目录相当于Windows中的文件夹,目录中存 ...
- 翻译:《实用的Python编程》04_01_Class
目录 | 上一节 (3.6 设计讨论) | 下一节 (4.2 继承) 4.1 类 本节介绍 class 语句以及创建新对象的方式. 面向对象编程(OOP) 面向对象编程是一种将代码组织成对象集合的编程 ...
- Python——input与raw_input的区别
区别一: raw_input():python2版本 input():python3版本 区别二: raw_input()不管是输数字还是字符串,结果都会以字符串的形式展现出来 input()则是 ...
- 为什么要从 Linux 迁移到 BSD1
为什么要从 Linux 迁移到 BSD1 作为一个操作系统,GNU/Linux 已经变得一团糟了,因为项目的分散性,内核的臃肿,以及商业利益的玩弄.从 GNU/Linux 迁移到 BSD 有几个技术上 ...
- WPF 基础 - xaml 语法总结
Attribute 与 Property 之间的区别 Property 对应着抽象对象身上的性状: Attribute 是针对标签的特征: 往往一个标签具有的 Attribute 对于它所代表的对象的 ...
- innerHTML,innerText
文本替换 <p id="p1">Hello World!</p><div>神经</div><h3 class="hh ...
- Dart简明教程
[前言]Dart语言是使用flutter框架开发时候必备的语言,flutter是一个跨平台的框架,一套代码就可以完美实现安卓和ios两个平台,适配也很不错,Dart语言很友好,和java很类似,学习成 ...
- 文本编辑工具 Vim与压缩打包
vim一共有3种模式:一般模式.编辑模式和命令模式 一般模式下的移动光标 光标向左移动:h或者向左的方向键 光标向右移动:l或者向右的方向键光标向上移动:k或者向上的方向键光标向下移动:j或者向下的方 ...