博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hiho_100_八数码
阅读量:4677 次
发布时间:2019-06-09

本文共 4111 字,大约阅读时间需要 13 分钟。

题目大意

    8数码问题,在3x3的矩阵中填入0-8九个数字,0可以和它相邻的数字进行交换。从初始状态到达状态F(3x3的方格从上到下,从左到右,形成的数字串为123456780)所需要最少移动的次数。

题目分析

    将3x3矩阵中的当前情形记为一个状态,用9个字符表示。然后根据方格0和它相邻的方格交换来进行状态的转移。可以采用广度优先的方式来进行搜索遍历,直到到达状态F,或者将所有的可能情况都遍历过来。 

    那么,如何判断一个状态是否被遍历过了呢?由于 用9个字符表示状态,每个字符有0-8 共9种可能,因此总共的情形为 9^9 = 387420489,空间复杂度太高,因此需要压缩: 由于9个方格中的数字均不相同,那么通过移动方格能够达到的合理的状态数就只有 9! =362880. 复杂度就可以接受了。因此需要实现将 0-8的一个排列定位到它在0-8全排列中的位置。 
    通过康托展开来实现:

康托展开法, 长度为n的排列 num[1,2....n],其在n的全排列中的序号为 

X = a[1](n-1)! + a[2](n-2)! +... +a[n]*0!; 
其中a[i] 表示在num[i+1, ...n]中比num[i]小的数量

    将空间进行压缩之后,可以用广度优先搜索来解决,但是也可以通过A-star 算法来进行优化: 

对每个状态都维护一个 F = G + H,表示该状态的代价。 G表示从初始状态到达该状态所花费的代价,H表示从该状态到达终点状态的估计代价。要求估计代价 H 一定小于等于 从该状态到达终点状态的实际代价! 
将当前可进入的状态按照F进行排序,选择F最小的那个进行扩展。 
H 可以通过估计函数来获得,本题中的估计函数就可以设置为 当前3x3矩阵中方格中的数字和最终状态对应方格中数字不同的方格的总数目。很容易证明 H 一定小于等于 实际从该状态到达终点状态的代价。

实现

#include
#include
#include
#include
using namespace std;char init_digit[3][3];bool visited[362890];struct Node{ char digit[3][3]; //状态记录 int g; //从起始状态到达该状态,已经花费的代价 int f; //该状态的价值, f = g + h(估价函数)};struct Cmp{ bool operator()(const Node& node1, const Node& node2){ return node1.f > node2.f; }};void Init(){ memset(visited, false, sizeof(visited));}//康托展开法, 长度为n的排列 num[1,2....n],其在n的全排列中的序号为//X = a[1]*(n-1)! + a[2]*(n-2)! +... +a[n]*0!;//其中a[i] 表示在num[i+1, ...n]中比num[i]小的数量/*逆康托展开X = a[1]*(n-1)! + a[2]*(n-2)! + ... + a[n]*0!, a[i] 表示 num[i+1, ... n]中小于a[i]的数目已知X,求出对应的 num[1,2...n]可知, a[i]肯定 <= n - i. 则 a[i]*(n-i)! <= (n-i)*(n-i)!, 那么 a[i+1]*(n-i-1)! + a[i+2]*(n-i-2)! + ... a[n]*0!<= (n-i-1)*(n - i - 1)! + (n-i-2)*(n - i - 2)! + .... 1*1! + 0*0!由数学归纳法可以知道, 1*1! < 2!, 1*1! + 2*2! < 3!, .... 因此(n-i-1)*(n - i - 1)! + (n-i-2)*(n - i - 2)! + .... 1*1! + 0*0! < (n-i)!a[i+1]*(n-i-1)! + a[i+2]*(n-i-2)! + ... a[n]*0! < (n-i)!因此, X / (n-1)! 的商c 即为 a[1], X / (n-1)! 的余数 r / (n-2)! 的商即为 a[2]....*/int digit2Int(char arr[3][3]){ // arr[0][0], arr[0][1] ... arr[2][2] 记为 num[1], num[2] ... num[9] int result = 0, t = 1; for (int i = 8; i >= 0; i--){ int row = i / 3, col = i % 3; int k = 0; for (int j = i + 1; j < 9; j ++) k += (arr[j / 3][j % 3] < arr[row][col]); result += k*t; t *= (9 - i); } return result;}int Estimate(char arr[3][3]){ int sum = 0; for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ if (3 * i + j == 8) continue; if (arr[i][j] != 3 * i + j + '1') sum++; } } return sum;}bool Succeed(char arr[3][3]){ for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ int target = (3 * i + j + 1) % 9; if (arr[i][j] != target + '0') return false; } } return true;}int move_step[4][2] = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } };int Search(){ priority_queue
, Cmp> pq; //queue
pq; int X = digit2Int(init_digit); visited[X] = true; Node node; for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ node.digit[i][j] = init_digit[i][j]; } } node.g = 0; node.f = 0 + Estimate(node.digit); pq.push(node); while (!pq.empty()){ //node = pq.front(); node = pq.top(); pq.pop(); if (Succeed(node.digit)) return node.g; char cur_digit[3][3]; int cur_g = node.g; int zero_r = 0, zero_c = 0; for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ cur_digit[i][j] = node.digit[i][j]; if (cur_digit[i][j] == '0'){ zero_r = i; zero_c = j; } } } for (int i = 0; i < 4; i++){ int next_r = zero_r + move_step[i][0]; int next_c = zero_c + move_step[i][1]; if (next_r >= 0 && next_r <= 2 && next_c >= 0 && next_c <= 2){ memcpy(node.digit, cur_digit, sizeof(cur_digit)); node.digit[next_r][next_c] = '0'; node.digit[zero_r][zero_c] = cur_digit[next_r][next_c]; int X = digit2Int(node.digit); if (visited[X]) continue; visited[X] = true; node.g = cur_g + 1; node.f = node.g + Estimate(node.digit); pq.push(node); } } } return -1;}int main(){ int T; scanf("%d", &T); while (T--){ for (int i = 0; i < 3; i++){ getchar(); scanf("%c %c %c", &init_digit[i][0], &init_digit[i][1], &init_digit[i][2]); } Init(); int step = Search(); if (step == -1) printf("No Solution!\n"); else printf("%d\n", step); } return 0;}

 

转载于:https://www.cnblogs.com/gtarcoder/p/5539345.html

你可能感兴趣的文章
3大主流NoSQL数据库性能对比测试报告
查看>>
pandas.DataFrame对行和列求和及添加新行和列
查看>>
【转载】后缀自动机学习总结
查看>>
YTU 2896: J--Zipper
查看>>
jQuery 源码分析 7: sizzle
查看>>
程序员如何打造属于自己的云笔记服务
查看>>
Hadoop守护进程【简】
查看>>
VMware ESXi-6.7——使用
查看>>
Java中map集合系列原理剖析
查看>>
Python Tornado初学笔记之数据库(二)
查看>>
二叉树C语言
查看>>
jQuery操作json数据
查看>>
记忆讲师石伟华微信公众号2018所有文章汇总(待更新)
查看>>
Vue2.0选中当前鼠标移入移除加样式
查看>>
迷宫C描述——栈的举例
查看>>
Html5 tips
查看>>
Android——KEYCODE列表
查看>>
cf251.2.C (构造题的技巧)
查看>>
Suse碎碎念
查看>>
C#面向对象基础(三) 属性
查看>>