逆向bfs搜索打表+康拓判重
HDU 1043八数码问题
八数码,就是1~8加上一个空格的九宫格,这道题以及这个游戏的目标就是把九宫格还原到从左到右从上到下是1~8然后最后是空格。
没了解康托展开之前,这道题怎么想都觉得很棘手,直接搜索的话也不知道怎么剪枝,而且判重也不可能开一个9维的数组,空间也不允许,所以先了解康托展开是无可厚非的第一步,这里就引用一下大佬的介绍,很简单很实用的关于全排列的一个东西
学会康托展开之后这道题就有很多解法了,很多是用A*的,不过这个我还没学会,只能弱弱的用万能的搜索来暴力过一切了,当然搜索的做法也有几个,直接暴力的正向搜索单组测试数据是可以的,单多组测试数据的话还是会超时,还有种双向bfs的做法,也就是把当前的数列和我们要的目标数列同时加入队列,然后两个相遇时就可以了。
不过我个人觉得那两个写起来比较麻烦不好处理,所以我还是采用一个逆向的bfs来打表,为什么可以打表的,了解康托展开后我们可以知道,这题的全排列最多也就9!,那我们完全可以预处理一下,由目标状态去跑到其他状态,把每个状态的康托展开的值作为它的一个编号,由此打表,具体的如代码
#include<cstdio>
#include<queue>
using namespace std;
const int dir[][]={{,},{,},{,-},{-,}};
const char leg[]={'l','u','r','d'};//因为是逆回去的,所以方向是反的
char s[];
int jc[]={},sm[];
struct Way{
char ans;
int f;
Way(){
f=-;
}
}w[];
struct Node{
int num[];
int kt,p;//康托值,x的位置
};
int kangtuo(int *a)//康托展开
{
int ans=;
for(int i=;i<;i++)
{
int k=;
for(int j=i+;j<;j++)
if(a[i]>a[j])
k++;
ans+=k*jc[-i];
}
return ans;
}
void bfs()
{
queue<Node> q;
Node b;
for(int i=;i<;i++)
b.num[i]=i;
b.kt=,b.p=;
q.push(b);
while(!q.empty())
{
Node e=q.front();
q.pop();
for(int i=;i<;i++)
{
int dx=e.p/+dir[i][];//二维比价好处理位置变化
int dy=e.p%+dir[i][];
if(dx>=&&dx<&&dy>=&&dy<)
{
b=e;b.p=dx*+dy;
int t=b.num[e.p];b.num[e.p]=b.num[b.p];b.num[b.p]=t;
b.kt=kangtuo(b.num);
if(w[b.kt].f==-)
{
w[b.kt].f=e.kt;
w[b.kt].ans=leg[i];
q.push(b);
}
}
}
}
}
int main()
{
for(int i=;i<=;i++)
jc[i]=jc[i-]*i;
bfs();
while(~scanf("%s",s))
{
for(int i=;i<;i++)
scanf("%s",s+i);
for(int i=;i<;i++)
if(s[i]>=''&&s[i]<='')
sm[i]=s[i]-'';
else
sm[i]=;
int kt=kangtuo(sm);
if(w[kt].f==-)//没遍历到这个状态
printf("unsolvable\n");
else
{
while(kt)//回溯输出答案
{
printf("%c",w[kt].ans);
kt=w[kt].f;
}
printf("\n");
}
}
return ;
}
代码千万条,自觉第一条,复制粘贴爽,打铁泪两行
既然涉及到八数码,最后再补充一个结论,怎么直接判断八数码有没有解,这涉及到逆序数,目标状态1~8的逆序数是0,而上下左右的变换并不会改变逆序数的奇偶性,(这里说的逆序数是不计x的)
所以结论就是,序列的奇偶性要和目标状态一致。
逆向bfs搜索打表+康拓判重的更多相关文章
- 八数码问题+路径寻找问题+bfs(隐式图的判重操作)
Δ路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条凑够初始状态到终止问题的最优路径, 而不是像回溯法那样找到一个符合某些要求的解. 八数码问题就是路径查找问题背景下的经典训练题目. 程序框架 p ...
- hdu 5012 bfs --- 慎用STL 比方MAP判重
http://acm.hdu.edu.cn/showproblem.php?pid=5012 发现一个问题 假设Sting s = '1'+'2'+'3'; s!="123"!!! ...
- poj3635 FULL tank(TLE) 有限制的最短路(BFS搜索)。
用的BFS+优先队列+二进制压缩状态判重+链式前向星, TLE,好像有人这样过了...好像要用A*算法,还不太会,所以暂时放弃.但是也学会了很多,学习了链式前向星,更深理解了BFS求最优的时候,什么时 ...
- BFS(四):搜索状态判重
在采用广度优先算法进行搜索时,一个需要重点注意的是在搜索过程中判重和去重.前面介绍的几个例子中,判重都较简单,如采用vis[]数组,若vis[i]==0,则i未访问过,i入队列:若vis[i]!=0, ...
- UVA 10651 Pebble Solitaire(bfs + 哈希判重(记忆化搜索?))
Problem A Pebble Solitaire Input: standard input Output: standard output Time Limit: 1 second Pebble ...
- BFS以及hash表判重的应用~
主要还是讲下hash判重的问题吧 这道题目用的是除法求余散列方式 前几天看了下算法导论 由于我们用的是线性再寻址的方式来解决冲突问题 所以hash表的大小(余数的范围)要包含我们要求的范围 对mod的 ...
- 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 ...
- hdu 4444 Walk (离散化+建图+bfs+三维判重 好题)
Walk Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submi ...
- HDU1043 Eight(八数码:逆向BFS打表+康托展开)题解
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
随机推荐
- 学习GTK+ (1) ——编写helloworld
环境 我使用的是新安装的manjaro 18.1 (kde版),安装新系统后后直接可以开始写代码,不需要安装各种调用的库等. 推荐一个网站,gnome开发者 https://developer.gno ...
- 使用Golang时遇到的一些坑
1. [致命]不是所有Panic都能捕获 我们知道Golang给开发人员提供recover()机制,对堆栈异常(panic)进行捕获并自定义其处理逻辑.下面举个例子: 构造一个除0的异常场景: 输出结 ...
- xshell和xftp过期解决办法
去官网 xshell:https://www.netsarang.com/download/down_form.html?code=522 xftp:https://www.netsarang.com ...
- CodeFirst与EntityFramework【续】
3. 实现一对一的关系.在介绍一对多关系和多对多关系时,大家应该已经注意到了只要存在依赖关系的两个类的定义中包含对方的实例或实例的集合,Entity Framework Code First会自 ...
- sql简易教程
讲干货,不啰嗦,本教程主要基于Mysql数据库,讲解sql的基本使用. 数据库主要包括增.删.改.查等基本操作,以下为设计到的常用的sql语句: 一.查 1.select 语法查询 SELECT co ...
- rabbitmq 使用PhpAmqpLib
rabbitmq类 rabbitmq.php <?php require_once __DIR__ . '/vendor/autoload.php'; use PhpAmqpLib\Connec ...
- git回退到历史版本
问题描述 在开发的过程中,想要修改一个参数的命名.然后修改各种地方,并且push上码云的远程仓库.然后突然发现还要改很多地方,突然后悔不想改动了.那该怎么办呢? 处理步骤 回退本地的git版本 将本地 ...
- win10家庭版设置移动热点出现“我们无法设置移动热点”
寝室wifi卡到爆炸, 买了一个360随身WiFi,可是360随身WiFi烧坏了 ...然后我就一个星期没玩游戏了 今天本来想开电脑的wifi试一试,结果发现无法设置热点 纳闷了 百度一下,发现都 ...
- Hadoop_25_MapReduce实现日志清洗程序
1.需求: 对web访问日志中的各字段识别切分,去除日志中不合法的记录,根据KPI统计需求,生成各类访问请求过滤数据 2.实现代码: a) 定义一个bean,用来记录日志数据中的各数据字段 packa ...
- php函数copy和rename的区别
copy ( string source, string dest )将文件从 source 拷贝到 dest.如果成功则返回 TRUE,失败则返回 FALSE. 如果要移动文件的话,请用 renam ...