HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】
本题有写法好几个写法,但主要思路是BFS:
No。1
采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重。如果只进行单向会超时。
No。2
采用hash进行判重,宽搜采用单向就可以AC。
No。3
运用康拓展开进行判重,即使采用单向宽搜时间效率也很高。
哈希是想到了,但是我们应该选择什么哈希函数呢,看了网上一些神牛利用的是"康托展开",也就是利用全排列都有一个对应的整数,利用哈希函数把状态压缩成整数,这样就可以做到每一个整数都是唯一对应一个状态,那么这个时候就把哈希做完了。
Eight
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 29838 Accepted Submission(s): 7831
Special Judge
Problem Description
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
Input
You will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output
You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdruldr
Source
South Central USA 1998 (Sepcial Judge Module By JGShining)
【代码】:
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<cctype>
#include<stack>
#include<sstream>
#include<list>
#include<assert.h>
#include<bitset>
#include<numeric>
#define debug() puts("+++++++++++++++++++++++++++++")
#define gcd(a,b) __gcd(a,b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a,b,sizeof(a))
#define sz size()
#define be begin()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
#define all 1,n,1
#define rep(i,x,n) for(int i=(x); i<(n); i++)
#define in freopen("in.in","r",stdin)
#define out freopen("out.out","w",stdout)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e18;
const int maxn = 1000000;
const int maxm = 1e6 + 10;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int dx[] = {-1,1,0,0,1,1,-1,-1};
const int dy[] = {0,0,1,-1,1,-1,1,-1};
const int d[6][3]={ {0,0,1},{0,0,-1},{-1,0,0},{1,0,0},{0,1,0},{0,-1,0} };
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,r
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
bool vis[maxn];
int cantor(int *s) //康拖展开求该序列的hash值
{
int sum = 0;
for(int i=0; i<9; i++)
{
int num = 0;
for(int j=i+1; j<9; j++)
if(s[j] < s[i]) num++;
sum += (num*fac[9-i-1]);
}
return sum + 1;
}
struct node
{
int s[9]; //数位- 2 3 4 1 5 x-0 7 6 8
int loc; //“0”的位置,把“x"当0
int status; //康拖展开的hash值
string path; //路径
}st,ed,now;
string path;
int aim = 46234; //123456780对应的康拖展开的hash值
char indexs[5]="udlr"; //正向搜索
bool check(int tx,int ty)
{
return (tx<0||tx>2||ty<0||ty>2);
}
bool bfs()
{
ms(vis,0);
queue<node> q;
q.push(now);
while(!q.empty())
{
st = q.front();
q.pop();
if(st.status==aim)
{
path = st.path;
return true;
}
int x = st.loc/3;
int y = st.loc%3;
for(int i=0; i<4; i++)
{
//0和四周交换
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(check(tx,ty)) continue;
ed = st;
ed.loc = tx * 3 + ty; //0和四周交换
ed.s[st.loc] = ed.s[ed.loc];
ed.s[ed.loc] = 0;
ed.status = cantor(ed.s);
if(!vis[ed.status])
{
vis[ed.status] = true;
ed.path+=indexs[i];
if(ed.status==aim)
{
path=ed.path;
return true;
}
q.push(ed);
}
}
}
return false;
}
/*
2 3 4 1 5 x 7 6 8
ullddrurdllurdruldr
*/
int main()
{
char ch;
while(cin>>ch)
{
if(ch=='x') {now.s[0]=0; now.loc=0;}
else now.s[0]=ch-'0';
for(int i=1;i<9;i++)
{
cin>>ch;
if(ch=='x')
{
now.s[i]=0;
now.loc=i;
}
else now.s[i]=ch-'0';
}
now.status=cantor(now.s);//234150768——>
if(bfs()) cout<<path<<endl;
else cout<<"unsolvable"<<endl;
}
}
//思路: 单向bfs()+哈希判重+路径输出(由于POJ数据只有一组,这个方法可以在POJ上面A,其它oj不能A )
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <stack>
#include <queue>
#include <cmath>
using namespace std;
#define MAXN 400000
struct State{
int state[9];
int pos;//空格位置
char ch[50];//记录原始状态到达当前状态的路径(数组不能开太大不然超内存)
}s[MAXN];//每一个状态对应一个结构体
int factor[9] = {1,1,2,6,24,120,720,5040,40320};//阶乘数组
int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};//方向数组
char dirtion[4] = {'u' , 'r' , 'd' , 'l'};
int vis[MAXN];//标记某个状态是否被走过
int start;//保存原始输入状态的哈希值
State star;//原始状态对应的结构体
queue<int>q;//这里不能直接放结构体,不然肯定超时
//哈希映射
int Hash(int s[]){
int i , j , temp , num;
num = 0 ;
for(i = 0 ; i < 9 ; i++){
temp = 0;
for(j = i+1 ; j < 9 ; j++){
if(s[j] < s[i]) temp++;
}
num += factor[8-i]*temp;
}
return num;
}
//广搜
bool Bfs(){
while(!q.empty()) q.pop();
memset(vis , 0 , sizeof(vis));
start = Hash(star.state);
vis[start] = 1;
s[start] = star;
q.push(start);
while(!q.empty()){
State cur = s[q.front()];
q.pop();
int x , y , r , c;
x = cur.pos/3 ; y = cur.pos%3;
for(int i = 0 ; i < 4 ; i++){
r = x+dir[i][0] ; c = y+dir[i][1];
if(r < 0 || c < 0 || r >= 3 || c >= 3) continue;
State tmp = cur;
tmp.state[tmp.pos] = tmp.state[3*r+c];//原先空格位置换成新的编号
tmp.pos = 3*r+c ; tmp.state[tmp.pos] = 9;//重新更新空格位置
int hash = Hash(tmp.state);//求出当前哈希值
if(vis[hash]) continue;
vis[hash] = 1;
int len = strlen(cur.ch);//求出前一个状态的路径长度
tmp.ch[len] = dirtion[i];//更新路径
s[hash] = tmp;//赋值
if(hash == 0){//如果搜索到目标节点直接输出退出
printf("%s\n" , s[hash].ch) ; return 1;
}
q.push(hash);//入对列
}
}
return 0;
}
int main(){
char c;
while(scanf("%c" , &c) != EOF){
if(c == 'x'){ star.state[0] = 9 ; star.pos = 0;}
else star.state[0] = c-'0';
for(int i = 1 ; i < 9 ; i++){
scanf(" %c" , &c);
if(c == 'x'){ star.pos = i ; star.state[i] = 9;}
else star.state[i] = c-'0';
}
getchar();
int flag = Bfs();
if(!flag) printf("unsolvable\n");//无解的情况
}
return 0;
}
HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】的更多相关文章
- hdu 1043 Eight 经典八数码问题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 The 15-puzzle has been around for over 100 years ...
- HDU 1043 Eight(八数码)
HDU 1043 Eight(八数码) 00 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Descr ...
- hdu 1043 Eight (八数码问题)【BFS】+【康拓展开】
<题目链接> 题目大意:给出一个3×3的矩阵(包含1-8数字和一个字母x),经过一些移动格子上的数后得到连续的1-8,最后一格是x,要求最小移动步数. 解题分析:本题用BFS来寻找路径,为 ...
- 八数码问题+路径寻找问题+bfs(隐式图的判重操作)
Δ路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条凑够初始状态到终止问题的最优路径, 而不是像回溯法那样找到一个符合某些要求的解. 八数码问题就是路径查找问题背景下的经典训练题目. 程序框架 p ...
- hdu 1043(经典搜索)
题意: 给你一个初始的图,然后每次输入一个图,要求移动x最小的步数达到和初始图一样,输出路径 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 5 6 7 8 5 6 7 8 5 6 7 ...
- hdu1043 经典的八数码问题 逆向bfs打表 + 逆序数
题意: 题意就是八数码,给了一个3 * 3 的矩阵,上面有八个数字,有一个位置是空的,每次空的位置可以和他相邻的数字换位置,给你一些起始状态 ,给了一个最终状态,让你输出怎么变换才能达到目的. 思路: ...
- hdu Minimum Transport Cost(按字典序输出路径)
http://acm.hdu.edu.cn/showproblem.php? pid=1385 求最短路.要求输出字典序最小的路径. spfa:拿一个pre[]记录前驱,不同的是在松弛的时候.要考虑和 ...
- HDU1043 Eight(八数码:逆向BFS打表+康托展开)题解
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- HDOJ-1043 Eight(八数码问题+双向bfs+高效记录路径+康拓展开)
bfs搜索加记录路径 HDOJ-1043 主要思路就是使用双向广度优先搜索,找最短路径.然后记录路径,找到结果是打印出来. 使用康拓序列来来实现状态的映射. 打印路径推荐使用vector最后需要使用a ...
随机推荐
- 除了基本类型,其余类型基本上大部分new出来 java.sql 包下面要不需要new
除了基本类型,其余类型基本上大部分new出来 java.sql 包下面要不需要new
- Event loop的macro task和micro task
macrotask在一些文章中也被直接称为task. 一个宿主环境只有一个事件循环,但可以有多个任务队列.宏任务队列(macro task)与微任务队列(micro task)就是其中之二. 每次事件 ...
- NAS星云链 入门之从零开发第一个DAPP
应该有很多小伙伴和我一样,一直想去入手学习区块链,但是总无从下手,有些概念感觉理解了,有感觉没理解.其实这都是“没实践”的锅. 所谓看十遍不如想一遍,想一遍不如做一遍.这不最近星云链nebulas正有 ...
- Android-使用ViewFlipper实现轮番切换广告栏
所谓的轮番切换广告栏,指的是下面这个东西,笔主不知道该怎么确切描述这货... 笔主没有百度研究过其他大牛是怎么实现这个功能的,在这里笔主充分发挥DIY精神,利用ViewFlipper闭门土制了一个,下 ...
- mysql共享表空间和独立表空间
innodb这种引擎,与MYISAM引擎的区别很大.特别是它的数据存储格式等. 对于innodb的数据结构,首先要解决两个概念性的问题: 共享表空间以及独占表空间. 什么是共享表空间和独占表空间 共享 ...
- JavaScript 被忽视的细节
语句/表达式 换个角度理解语句(statemaents)和表达式(expressions):表达式不会改变程序的运行状态,而语句会.还有一种叫做表达式语句,可以理解为表达式和语句的交集,如({a:1} ...
- 解决在ios下不能自动播放音频的问题
在ios下面是不允许自动播放音频这个操作的,不过我们可以使用微信提供的sdk来做到自动播放音乐的功能 wx.ready(()=>{}) 引入微信的sdk,之后在回调函数里面执行主动触发背景音乐播 ...
- netty入门代码学习
服务端代码: package com.lsp.netty; /** * @author lishupeng * @create 2017-05-27 下午 3:48 **/ import io.net ...
- HDU1878 欧拉回路---(并查集+图论性质)
http://acm.hdu.edu.cn/showproblem.php?pid=1878 欧拉回路 Time Limit: 2000/1000 MS (Java/Others) Memory ...
- python基础(3)_列表、元组、字典
一.列表 定义:[ ] 内以逗号分隔,按照索引,存放各种数据类型,每个位置代表一个元素 特性: > 可存放多个值 > 可修改指定索引位置对应的值,可变 > 按照从左到右的顺序定义列表 ...