题目:

简单介绍一下八数码问题:
        在一个3×3的九宫格上,填有1~8八个数字,空余一个位置,例如下图:

1 2 3
4 5 6
7 8  


        在上图中,由于右下角位置是空的,你可以移动数字,比如可以将数字6下移一位:

1 2 3   1 2 3
4 5 6 4 5  
7 8     7 8 6


        或者将数字8右移一位:

1 2 3   1 2 3
4 5 6 4 5 6
7 8     7   8


        1~8按顺序排列的情况称为“初始状态”(如最上方图)。“八数码问题”即是求解对于任意的布局,将其移动至“初始状态”的方法。 
        给定一个现有的九宫格布局,请输出将它移动至初始状态的移动方法的步骤。

输入:

 输入包含多组数据,处理至文件结束。每组数据占一行,包含8个数字和表示空位的‘x’,各项以空格分隔,表示给定的九宫格布局。 
        例如,对于九宫格

1 2 3
  4 6
7 5 8


        输入应为:1 2 3 x 4 6 7 5 8

 输出:

对于每组输入数据,输出一行,即移动的步骤。向上、下、左、右移动分别用字母u、d、l、r表示;如果给定的布局无法移动至“初始 状态”,请输出unsolvable。
        如果有效的移动步骤有多种,输出任意即可。

样例:

分析:双向BFS,简单来说就是同时进行两个BFS,但每个BFS的vis数组有了新的用途即判断另一个BFS是否达到此BFS扩展到的此刻的点,若抵达即连通。

unsolvable的情况用逆序数的奇偶性判断,因为目标状态12345678逆序数为0,所以当前态的逆序数必为偶

用康托展开记录字典序用于状态压缩(hash)

 #include<iostream>
#include<sstream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<numeric>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<cctype>
#define PI acos(-1.0)
const int INF = 0x3f3f3f3f;
const int NINF = -INF - ;
typedef long long ll;
using namespace std;
int fac[] = {, , , , , , , , , };
int vis1[], vis2[];
int eda[]={ , , , , , , , , };
string path[];
int dx[] = {, -, , }, dy[] = {, , -, };
char p1[] = {'d', 'u', 'l', 'r'}, p2[] = {'u', 'd', 'r', 'l'};
struct node
{
int s[];
int cur, n;//cur目前x所在位置,n为hash值
}st;
int cantor(int *s)//康托展开
{
int sum = ;
for (int i = ;i < ; ++i)
{
int k = ;
for (int j = i + ; j < ; ++j)
if( s[j] < s[i]) k++;
sum += k * fac[ - i];
}
return sum;
}
void bfs()
{
memset(vis1, , sizeof(vis1));
memset(vis2, , sizeof(vis2));
queue<node> q1, q2;
st.n = cantor(st.s);
q1.push(st);
vis1[st.n] = ;
path[st.n] = "";//重要
node ed;
memcpy(ed.s, eda, sizeof(ed.s));
ed.n = cantor(ed.s);
ed.cur = ;
path[ed.n] = "";
q2.push(ed);
vis2[ed.n] = ;
while (q1.size() || q2.size())
{
node temp1 = q1.front();
q1.pop();
int x1 = temp1.cur / , y1 = temp1.cur % ;
for (int i = ; i < ; ++i)
{
int nx = x1 + dx[i], ny = y1 + dy[i];
if (nx < || nx > || ny < || ny > ) continue;
node rec = temp1;
rec.cur = nx * + ny;
swap(rec.s[temp1.cur], rec.s[rec.cur]);
rec.n = cantor(rec.s);
if (vis2[rec.n])
{
reverse(path[rec.n].begin(), path[rec.n].end());
cout << path[temp1.n] << p1[i] << path[rec.n] << endl;
return;
}
if (!vis1[rec.n])
{
vis1[rec.n] = ;
path[rec.n] = path[temp1.n];
path[rec.n] += p1[i];
q1.push(rec);
}
}
node temp2 = q2.front();
q2.pop();
int x2 = temp2.cur / , y2 = temp2.cur % ;
for (int i = ; i < ; ++i)
{
int nx = x2 + dx[i], ny = y2 + dy[i];
if (nx < || nx > || ny < || ny > ) continue;
node rec = temp2;
rec.cur = nx * + ny;
swap(rec.s[temp2.cur], rec.s[rec.cur]);
rec.n = cantor(rec.s);
if (vis1[rec.n])
{
reverse(path[temp2.n].begin(), path[temp2.n].end());
cout << path[rec.n] << p2[i] << path[temp2.n] << endl;
return;
}
if (!vis2[rec.n])
{
vis2[rec.n] = ;
path[rec.n] = path[temp2.n];
path[rec.n] += p2[i];
q2.push(rec);
}
}
}
} int main()
{
char c;
while(cin >> c)
{
if(c == 'x')
{
st.s[] = ;
st.cur = ;
}
else st.s[] = c - '';
for (int i = ; i < ; ++i)
{
cin >> c;
if ( c == 'x')
{
st.s[i] = ;
st.cur = i;
}
else st.s[i] = c - '';
}
int k = ;
for(int i = ; i < ; ++i)
{
if (st.s[i])
{
for (int j = i + ; j < ; ++j)
if (st.s[j] < st.s[i] && st.s[j]) k++;
}
}
if(k & ) cout<< "unsolvable" << endl;
else bfs();
}
return ;
}

HDU1043 Eight的更多相关文章

  1. ACM/ICPC 之 BFS-广搜进阶-八数码(经典)(POJ1077+HDU1043)

    八数码问题也称为九宫问题.(本想查查历史,结果发现居然没有词条= =,所谓的历史也就不了了之了) 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个 ...

  2. HDU-1043 Eight八数码 搜索问题(bfs+hash 打表 IDA* 等)

    题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原 ...

  3. 后缀数组:HDU1043 Longest Common Substring

    Longest Common Substring Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java ...

  4. HDU1043 Eight(BFS)

    Eight(South Central USA 1998) Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d & ...

  5. 【双向广搜+逆序数优化】【HDU1043】【八数码】

    HDU上的八数码 数据强的一B 首先:双向广搜 先处理正向搜索,再处理反向搜索,直至中途相遇 visit 和 队列都是独立的. 可以用一个过程来完成这2个操作,减少代码量.(一般还要个深度数组) 优化 ...

  6. hdu1043

    #include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#inclu ...

  7. POJ1077&&HDU1043(八数码,IDA*+曼哈顿距离)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30127   Accepted: 13108   Special ...

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

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

  9. hdu-1043(八数码+bfs打表+康托展开)

    参考文章:https://www.cnblogs.com/Inkblots/p/4846948.html 康托展开:https://blog.csdn.net/wbin233/article/deta ...

  10. HDU1043 Eight(八数码:逆向BFS打表+康托展开)题解

    Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

随机推荐

  1. VUE路由history模式坑记--NGINX

    因微信分享和自动登录需要,对于URL中存在'#'的地址,处理起来比较坑(需要手动写一些代码来处理).还有可能会有一些隐藏的问题没被发现. 如果VUE能像其他(JSP/PHP)系统的路径一样,就不存在这 ...

  2. 《LeetCode-0004》 寻找两个有序数组的中位数-Median of Two Sorted Arrays

    题目给定两个大小为 m 和 n 的有序数组nums1和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)). 你可以假设 nums1 和 nums2 ...

  3. 16.copy_to定制组合field解决cross-fields搜索弊端

    主要知识点: 在index的mapping中加copy_to字段的方法 copy_to搜索方法     用most_fields策略,去实现cross-fields搜索,有3大弊端,为了解决这三个弊端 ...

  4. 为什么有些图像在显示前要除以255?(zhuan)

    imshow是用来显示图片的,如 >> I = imread('moon.tif'); >> figure,imshow(I); 而有时为了数据处理,要把读取的图片信息转化为更 ...

  5. 修改tomcat端口号的方法

    8080是Tomcat服务器的默认的端口号.我们可以通过修改Tomcat服务器的conf目录下的主配置文件server.xml来更改.用记事本打开server.xml文件,找到如下部分: 以下为引用的 ...

  6. linux服务器中不支持soap及bcmul函数的结局方法

    新的程序里用了webserice接口,部到服务器,先是提示:bcmul() 函数不可用,网上搜索一番,得知这是php的高精度函数,需要在编译php的时候加入此模块,于是在编译脚本里增添 “–enabl ...

  7. Expanding Rods POJ 1905 二分

    Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 17050   Accepted: 4503 Description When ...

  8. [bzoj1103][POI2007]大都市meg_dfs序_树状数组

    大都市meg bzoj-1103 POI-2007 题目大意:给定一颗n个点的树,m次操作.将一条路的边权更改成0:查询一个点到根节点的点权和.开始的时候所有边的边权都是1. 注释:$1\le n,m ...

  9. SSM(spring mvc+spring+mybatis)学习路径——1-1、spring入门篇

    目录 1-1 Spring入门篇 专题一.IOC 接口及面向接口编程 什么是IOC Spring的Bean配置 Bean的初始化 Spring的常用注入方式 专题二.Bean Bean配置项 Bean ...

  10. N天学习一个linux命令之umask

    前言 umask不是linux命令,而是shell内置的指令,俗称用户权限掩码,用于对用户创建的文件和目录设置默认权限.默认的权限掩码是0022,也就是说新创建的文件权限是0644,新创建的目录权限是 ...