题目:八数码

网址:http://poj.org/problem?id=1077

在一个3×3的网格中,1~8这8个数字和一个“X”恰好不重不漏地分布在这3×3的网格中。

例如:

1 2 3
X 4 6
7 5 8

在游戏过程中,可以把“X”与其上、下、左、右四个方向之一的数字交换(如果存在)。

我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 X

例如,示例中图形就可以通过让“X”先后与右、下、右三个方向的数字交换成功得到正确排列。

交换过程如下:

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

把“X”与上下左右方向数字交换的行动记录为“u”、“d”、“l”、“r”。

现在,给你一个初始网格,请你通过最少的移动次数,得到正确排列。

输入格式

输入占一行,将3×3的初始网格描绘出来。

例如,如果初始网格如下所示:

1 2 3

x 4 6

7 5 8

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

输出格式

输出占一行,包含一个字符串,表示得到正确排列的完整行动记录。如果答案不唯一,输出任意一种合法方案即可。

如果不存在解决方案,则输出”unsolvable”。

输入样例:
2  3  4  1  5  x  7  6  8
输出样例:
ullddrurdllurdruldr

很经典的一道广搜题目(A*)。核心就是如何保存状态。

  • 方法一:使用map来记录操作以及set判重。
  • 方法二:康托展开(早晚更新的)。
  • 方法三:hash表判重,码量较大。

STL代码如下:

#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define pii pair <int, int> using namespace std; const int dx[4] = {-1, 1, 0, 0};
const int dy[4] = {0, 0, -1, 1}; int st, ed = 123456780;
set <int> vis;
map <int, int> d, f;
void decode(int state, int *p)
{
for(int i = 0; i < 9; ++ i)
{
p[8 - i] = state % 10;
state /= 10;
}
return;
}
int encode(int *p)
{
int t = 0;
for(int i = 0; i < 9; ++ i)
{
t = (t << 3) + (t << 1);
t += p[i];
}
return t;
}
int gh(int *p)
{
int cost = 0;
for(int i = 0; i < 9; ++ i)
cost += abs(i / 3 - (p[i] - 1) / 3) + abs(i % 3 - (p[i] - 1) % 3); return cost;
}
void print(int state)
{
if(state == st) return;
int pre_state = f[state];
print(pre_state);
int i, p1[9] = {}, p2[9] = {}, t1 = -1, t2 = -1;
decode(state, p1), decode(pre_state, p2);
for(i = 0; i < 9; ++ i)
{
if(p1[i] == 0)
{
t1 = i;
break;
}
}
for(i = 0; i < 9; ++ i)
{
if(p2[i] == 0)
{
t2 = i;
break;
}
}
if(t1 < t2)
{
if(t1 - t2 == -1) putchar('l');
else putchar('u');
}
else
{
if(t2 - t1 == -1) putchar('r');
else putchar('d');
}
return;
}
bool valid(int x, int y)
{
if(x < 0 || x > 2 || y < 0 || y > 2) return false;
return true;
}
bool hash_table_judge(int state)
{
if(vis.count(state)) return false;
return true;
}
void hash_table_insert(int next_state, int state)
{
d[next_state] = d[state] + 1;
vis.insert(next_state);
f[next_state] = state;
return;
}
int bfs()
{
if(st == ed) return 0;
d.clear(), vis.clear(), f.clear();
queue <int> Q;
while(!Q.empty()) Q.pop();
int state, next_state, now, next, p[9], x, y;
memset(p, -1, sizeof(p)); hash_table_insert(st, 0);
d[st] = 0;
Q.push(st); while(!Q.empty())
{
state = Q.front();
Q.pop();
decode(state, p);
for(int i = 0; i < 9; ++ i)
{
if(p[i] == 0)
{
now = i;
x = i / 3, y = i % 3;
break;
}
}
for(int i = 0; i < 4; ++ i)
{
if(!valid(x + dx[i], y + dy[i])) continue;
next = (x + dx[i]) * 3 + (y + dy[i]);
swap(p[now], p[next]);
next_state = encode(p);
swap(p[now], p[next]);
if(!hash_table_judge(next_state)) continue;
hash_table_insert(next_state, state);
if(next_state == ed)
{
printf("%d\n", d[state]);
print(state);
return 1;
}
Q.push(next_state);
}
}
return -1;
}
int main()
{
string line;
getline(cin, line);
for(int i = 0; i < line.size(); ++ i)
{
if(line[i] == 'x')
{
line[i] = '0';
break;
}
}
stringstream ss(line);
int tmp;
st = 0;
for(int i = 0; i < 9; ++ i)
{
ss >> tmp;
st = (st << 3) + (st << 1);
st += tmp;
}
if(bfs() == -1) puts("unsolvable");
return 0;
}

hash表代码如下:

#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#define pii pair <int, int>
using namespace std;
const int maxn = 377777 + 5, mod = 377777;
const int dx[4] = {-1, 1, 0, 0};
const int dy[4] = {0, 0, -1, 1}; int st, ed = 123456780, head[maxn] = {}, next[maxn] = {}, table[maxn] = {}, tot = 0;
map <int, int> d, f;
void decode(int state, int *p)
{
for(int i = 0; i < 9; ++ i)
{
p[8 - i] = state % 10;
state /= 10;
}
return;
}
int encode(int *p)
{
int t = 0;
for(int i = 0; i < 9; ++ i)
{
t = (t << 3) + (t << 1);
t += p[i];
}
return t;
}
int hash_table_search(int state)
{
int val = state % mod;
for(int i = head[val]; i; i = next[i])
if(table[i] == state) return i;
return -1;
}
int gh(int *p)
{
int cost = 0;
for(int i = 0; i < 9; ++ i)
cost += abs(i / 3 - (p[i] - 1) / 3) + abs(i % 3 - (p[i] - 1) % 3); return cost;
}
void print(int state)
{
if(state == st) return;
int pre_state = f[state];
print(pre_state);
int i, p1[9] = {}, p2[9] = {}, t1 = -1, t2 = -1;
decode(state, p1), decode(pre_state, p2);
for(i = 0; i < 9; ++ i)
{
if(p1[i] == 0)
{
t1 = i;
break;
}
}
for(i = 0; i < 9; ++ i)
{
if(p2[i] == 0)
{
t2 = i;
break;
}
}
if(t1 < t2)
{
if(t1 - t2 == -1) putchar('l');
else putchar('u');
}
else
{
if(t2 - t1 == -1) putchar('r');
else putchar('d');
}
return;
}
bool valid(int x, int y)
{
if(x < 0 || x > 2 || y < 0 || y > 2) return false;
return true;
}
bool hash_table_judge(int state)
{
int val = state % mod;
for(int i = head[val]; i; i = next[i])
if(table[i] == state) return false; return true;
}
void hash_table_insert(int next_state, int state)
{
int val = next_state % mod;
table[++ tot] = next_state;
next[tot] = head[val];
head[val] = tot;
f[next_state] = state;
d[next_state] = d[state] + 1;
return;
}
int bfs()
{
if(st == ed) return 0;
d.clear(), f.clear();
queue <int> Q;
while(!Q.empty()) Q.pop();
int state, next_state, now, next, p[9], x, y;
memset(p, -1, sizeof(p)); hash_table_insert(st, 0);
d[st] = 0;
Q.push(st); while(!Q.empty())
{
state = Q.front();
Q.pop();
decode(state, p);
for(int i = 0; i < 9; ++ i)
{
if(p[i] == 0)
{
now = i;
x = i / 3, y = i % 3;
break;
}
}
for(int i = 0; i < 4; ++ i)
{
if(!valid(x + dx[i], y + dy[i])) continue;
next = (x + dx[i]) * 3 + (y + dy[i]);
swap(p[now], p[next]);
next_state = encode(p);
swap(p[now], p[next]);
if(!hash_table_judge(next_state)) continue;
hash_table_insert(next_state, state);
if(next_state == ed)
{
print(state);
return d[state];
}
Q.push(next_state);
}
}
return -1;
}
int main()
{
string line;
getline(cin, line);
for(int i = 0; i < line.size(); ++ i)
{
if(line[i] == 'x')
{
line[i] = '0';
break;
}
}
stringstream ss(line);
int tmp;
st = 0;
for(int i = 0; i < 9; ++ i)
{
ss >> tmp;
st = (st << 3) + (st << 1);
st += tmp;
}
if(bfs() == -1) puts("unsolvable");
return 0;
}

POJ1077 八数码问题的更多相关文章

  1. POJ1077 八数码 BFS

    BFS 几天的超时... A*算法不会,哪天再看去了. /* 倒搜超时, 改成顺序搜超时 然后把记录路径改成只记录当前点的操作,把上次的位置记录下AC..不完整的人生啊 */ #include < ...

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

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

  3. 由八数码问题引入。对BFS有更深考虑

    12号到今天共研究八数码问题poj1077,首先用的是普通BFS,遇到很多问题,开始用一个二级指针作为结构成员,知道了二级指针与二维数值名的不同!http://write.blog.csdn.net/ ...

  4. A*算法 -- 八数码问题和传教士过河问题的代码实现

    前段时间人工智能的课介绍到A*算法,于是便去了解了一下,然后试着用这个算法去解决经典的八数码问题,一开始写用了挺久时间的,后来试着把算法的框架抽离出来,编写成一个通用的算法模板,这样子如果以后需要用到 ...

  5. 八数码问题:C++广度搜索实现

    毕竟新手上路23333,有谬误还请指正. 课程设计遇到八数码问题(这也是一坨),也查过一些资料并不喜欢用类函数写感觉这样规模小些的问题没有必要,一开始用深度搜索却发现深搜会陷入无底洞,如果设定了深度限 ...

  6. BFS(八数码) POJ 1077 || HDOJ 1043 Eight

    题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...

  7. 双向广搜+hash+康托展开 codevs 1225 八数码难题

    codevs 1225 八数码难题  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description Yours和zero在研究A*启 ...

  8. UVALive 6665 Dragon’s Cruller --BFS,类八数码问题

    题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的). 分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可. 代码: #include <i ...

  9. P1379 八数码问题

    aoapc上的八数码问题,在luogu上也有类似的题,p1379,经典题目,lrj给出了一个算法,同时给出了三种判重的方法.本来想用std::queue改写一下,但是出了各种问题,只好抄代码ac掉这道 ...

随机推荐

  1. vue按需引入/全局引入echarts

    npm install echarts -S 1.按需引入 新建echarts.js公共引入 // 文件路径 @/lib/echarts.js 自行配置 // 加载echarts,注意引入文件的路径 ...

  2. php zip打包

    zip中加入文件 <?php $zip = new ZipArchive; if ($zip->open('test.zip', ZipArchive::OVERWRITE) === TR ...

  3. CF633(div.2)C. Powered Addition

    题目描述 http://codeforces.com/contest/1339/problem/C 给定一个长度为 \(n\) 的无序数组,你可以在第 \(x\) 秒进行一次下面的操作. 从数组选取任 ...

  4. 微信小程序常用的方法(留着用)

    function zero_fill_hex(num, digits) { let s = num.toString(16); while (s.length < digits) s = &qu ...

  5. Vulnhub DC-8靶机渗透

    信息搜集 nmap -sP 192.168.146.0/24 #主机发现 nmap -A 192.168.146.146 #Enable OS detection, version detection ...

  6. python爬取疫情数据详解

    首先逐步分析每行代码的意思: 这是要引入的东西: from os import path import requests from bs4 import BeautifulSoup import js ...

  7. 28.5 Integer-- int的包装类

    * 由于基本数据类型只能做一些简单的操作和运算,所以Java为我们封装了基本数据类型,为每种基本数据类型提供了包装类 * 包装类就是封装了基本数据类型的类,为我们提供了更多复杂的方法和一些变量 * * ...

  8. Silverlight 2.5D RPG游戏技巧与特效处理:(十一)AI系统

    Silverlight 2.5D RPG游戏技巧与特效处理:(十一)AI系统 作者: 深蓝色右手  来源: 博客园  发布时间: 2011-04-19 11:18  阅读: 1282 次  推荐: 0 ...

  9. BAT脚本编写要点_特殊字符

    BAT脚本编写要点(1)_特殊字符 分类: 其他 2011-03-20 00:58 5621人阅读 评论(0) 收藏 举报 脚本cdatecmdtreesystem 1. 点 与echo连用,作用是换 ...

  10. vue 本地调试跨域---带cookies(axios)

    cookise跨域第二期之便捷优雅的本地调试(axios) 1.打开config/index.js,在proxyTable中添写如下代码: proxyTable: { '/agent': { //使用 ...