题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043

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.

 
题意描述:给出一个3×3的矩阵(包含1~8数字和一个字母x),经过一些移动格子上的数后得到连续的1~8,最后一格是x,要求最小移动步数。
算法分析:经典的八数码问题。八数码属于搜索方面的问题,经典解法有bfs、A*、IDA*等等。网上资料很多,这里简单介绍一下A*。
A*:f=g+h函数。g表示从起点到当前点的移动步数,h表示对当前点到目标点的最小移动步数的预测。除去起点和目标点,我们走在任意一点上的时候,下一步很容易想到应该选择f较小的继续。(对于h的计算我们可以用曼哈顿距离公式)
康托展开:这道题里面的作用在于实施hash函数,对于当前这一步后得到一个新的矩阵,用康托展开公式计算这个矩阵的hash值,用在宽搜时判断。
还有一点优化的地方:判断当前矩阵是否可以达到目标矩阵(矩阵里两个数实施交换后,逆序数的奇偶性和目标矩阵一致才可以有机会达到目标矩阵)
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define inf 0x7fffffff
using namespace std;
const int maxn=;
const int M = +; struct node
{
int mase[][];
int x,y;
int f,g,h;
int flag;
friend bool operator < (node a,node b)
{
return a.f > b.f;
}
}start,tail;
int pre[M],v[M]; char str[]={'u','d','l','r' };
int Can[]={,,,,,,,, };
const int destination=;
int Cantor(node cur) ///康托展开
{
int an[],k=;
for (int i= ;i< ;i++)
for (int j= ;j< ;j++)
an[k++]=cur.mase[i][j];
int sum=;
for (int i= ;i< ;i++)
{
int k=;
for (int j=i+ ;j< ;j++)
if (an[i]>an[j]) k++;
sum += k*Can[-i-];
}
return sum+;
} int is_ok(node an) ///判断此时奇偶性
{
int a[],k=;
for (int i= ;i< ;i++)
for (int j= ;j< ;j++)
a[k++]=an.mase[i][j];
int sum=;
for (int i= ;i<k ;i++) if (a[i]!=)
for (int j= ;j<i ;j++)
if (a[j]!= && a[j]>a[i]) sum ++ ;
if (sum&) return ;
return ;
} void print(node cur)
{
string ans;
int sum=destination;
while (pre[sum] != -)
{
switch (v[sum]) {
case : ans += str[];break;
case : ans += str[];break;
case : ans += str[];break;
case : ans += str[];break;
}
sum=pre[sum];
}
int len=ans.size() ;
for (int i=len- ;i>= ;i--) putchar(ans[i]);
return ;
} pair<int,int> pii[];
int getH(node cur)
{
int r=,c=;
for (int i= ;i<= ;i++)
{
pii[i%].first=r ;
pii[i%].second=c;
c++;
if (c==) {r++;c=; }
}
int sum=;
for (int i= ;i< ;i++)
{
for (int j= ;j< ;j++)
{
int u=cur.mase[i][j];
sum += abs(pii[u].first-i)+abs(pii[u].second-j);
}
}
return sum;
} int vis[M];
int an[][]={-,, ,, ,-, , };
void A_star(node cur)
{
priority_queue<node> Q;
cur.g= ;cur.h=getH(cur);
cur.f=cur.g + cur.h ;
cur.flag=-;
Q.push(cur);
memset(vis,-,sizeof(vis));
memset(pre,-,sizeof(pre));
memset(v,-,sizeof(v));
vis[Cantor(cur) ]=;
while (!Q.empty())
{
cur=Q.top() ;Q.pop() ;
if (Cantor(cur)==destination)
{
// cout<<cur.g<<endl;
// for (int i=0 ;i<3 ;i++)
// {
// for (int j=0 ;j<3 ;j++)
// cout<<cur.mase[i][j]<<" ";
// cout<<endl;
// }
///输出序列
print(cur);
return ;
}
for (int i= ;i< ;i++)
{
tail.x=cur.x+an[i][];
tail.y=cur.y+an[i][];
int x=cur.x ,y=cur.y ;
for (int u= ;u< ;u++)
for (int v= ;v< ;v++)
tail.mase[u][v]=cur.mase[u][v];
if (tail.x<||tail.x>=||tail.y<||tail.y>=) continue;
swap(tail.mase[tail.x][tail.y],tail.mase[x][y]);
int sum=Cantor(tail);
if (vis[sum]==-)
{
if (is_ok(tail)==) continue;
vis[sum]=;
tail.g=cur.g+;
tail.h=getH(tail);
tail.f=tail.g+tail.h;
if (tail.x==x+) tail.flag=;
else if (tail.x==x-) tail.flag=;
else if (tail.y==y-) tail.flag=;
else if (tail.y==y+) tail.flag=;
pre[sum]=Cantor(cur);
v[sum]=i;
Q.push(tail);
}
}
}
return ;
} int main()
{
char str[];
while (gets(str))
{
int r=,c=;
int len=strlen(str);
int ok=;
for (int i= ;i<len ;i++)
{
if (str[i]>='' && str[i]<='')
{
start.mase[r][c]=str[i]-'';
c++;
if (c==) {r++;c=; }
}
else if (str[i]=='x')
{
start.mase[r][c]=;
start.x=r ;start.y=c ;
c++;
if (c==) {r++;c=; }
}
}
int sum=Cantor(start);
if (sum==destination) {printf("\n");continue; }
if (is_ok(start)==) {printf("unsolvable\n");continue; }
A_star(start);
printf("\n");
}
return ;
}

hdu 1043 Eight 经典八数码问题的更多相关文章

  1. HDU 1043 Eight(八数码)

    HDU 1043 Eight(八数码) 00 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)   Problem Descr ...

  2. 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 ...

  3. HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】

    本题有写法好几个写法,但主要思路是BFS: No.1 采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重.如果只进行单向会超时. No.2 采用hash进行判重,宽搜采用单向就可以AC. No.3 ...

  4. HDU1043 八数码(BFS + 打表)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 , 康托展开 + BFS + 打表. 经典八数码问题,传说此题不做人生不完整,关于八数码的八境界 ...

  5. hdu 1043 Eight(双向bfs)

    题意:经典八数码问题 思路:双向bfs ps:还有a*算法(还不会)等解法. 代码: #include<iostream> #include<stdio.h> #include ...

  6. HDU 1043 Eight 八数码问题 A*算法(经典问题)

    HDU 1043 Eight 八数码问题(经典问题) 题意 经典问题,就不再进行解释了. 这里主要是给你一个状态,然后要你求其到达\(1,2,3,4,5,6,7,8,x\)的转移路径. 解题思路 这里 ...

  7. Hdu 1043 Eight (八数码问题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1043 题目描述: 3*3的格子,填有1到8,8个数字,还有一个x,x可以上下左右移动,问最终能否移动 ...

  8. Eight POJ - 1077 HDU - 1043 八数码

    Eight POJ - 1077 HDU - 1043 八数码问题.用hash(康托展开)判重 bfs(TLE) #include<cstdio> #include<iostream ...

  9. HDU 1043 Eight (BFS&#183;八数码&#183;康托展开)

    题意  输出八数码问题从给定状态到12345678x的路径 用康托展开将排列相应为整数  即这个排列在全部排列中的字典序  然后就是基础的BFS了 #include <bits/stdc++.h ...

随机推荐

  1. C#语法基础和面向对象编程

    1.C#语法基础 http://www.cnblogs.com/tonney/archive/2011/03/16/1986456.html 2.C#与面向对象基础 很棒的资源,简明扼要,介绍的非常清 ...

  2. 在EF的code frist下写稳健的权限管理系统:界面设计(四)

    基本都是采用pure设计(中文官网:http://purecss.org,英文官网:http://purecss.io).pure只是一个简单强大的cssUI库,支持响应式设计,适合自己设计或者给美工 ...

  3. [转载]--类unix系统如何初始化shell

    Shell的配置文件 当我们在linux中打开一个shell的时候,系统会读取相关的配置文件来初始化shell(其他unix-like OS也一样).配置文件包括以下这些: 1. 全局配置(对所有用户 ...

  4. eval和new Function的区别

    eval和new Function都可以动态解析和执行字符串.但是它们对解析内容的运行环境判定不同. var a = 'global scope' function b(){ var a = 'loc ...

  5. 同花顺面试经验(搜索引擎C++后台研发)

    1.为什么要网页查重 ,怎么查重 2.软 硬cache是指什么 3.多线程编程:互斥变量 和 条件变量 函数怎么写 4.网络编程: epoll干什么的,有什么功能 5.网络编程:select 和 ep ...

  6. 浅谈Objective-C异常处理

    -----<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培 ...

  7. SQL基础篇——如何搭建一个数据库

    特别提醒:所有的新建数据库,表,行,列都可以通过对象资源管理器操作,下面所讲的为查询操作方法 一.新建数据库 使用CREATE DATABASE语句建立数据库: 新建查询-- CREATE DATAB ...

  8. 文件系统 第八次迭代 VFS相关说明

    麻烦访问evernote链接 http://www.evernote.com/shard/s133/sh/53e5b5ac-1192-4910-8bd5-6886218562af/59516c32a5 ...

  9. greenDao生成的实体类无法存放JsonArray的解决方法

    今天在解析Json数据的时候,发现我们用greenDao生成的实体类只能是基本数据类型,而我请求回来的json数据里面还包含了jsonArray. 下面是json的数据格式 "content ...

  10. hdu 5272 Dylans loves numbers

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5272 Dylans loves numbers Description Who is Dylans?Y ...