【HDU No. 3567】八数码 II Eight II
创始人
2024-01-21 01:06:51
0

【HDU No. 3567】八数码 II Eight II

杭电OJ 题目地址

在这里插入图片描述

【题意】

八数码,也叫作“九宫格”,来自一个古老的游戏。在这个游戏中,你将得到一个3×3的棋盘和8个方块。方块的编号为1~8,其中一块方块丢失,称之为“X”。“X”可与相邻的方块交换位置。用符号“r”表示将“X”与其右侧的方块进行交换,用“l”表示左侧的方块,用“u”表示其上方的方块,用“d”表示其下方的方块。

在这里插入图片描述

棋盘的状态可以用字符串S表示,使用下面显示的规则。

在这里插入图片描述

问题是使用“r”“u”“l”“d”操作列表可以将棋盘的状态从状态A转到状态B,需要找到满足以下约束的结果:

  1. 在所有可能的解决方案中,它的长度最小;
  2. 它是所有最小长度解中词典序最小的一个。

【输入输出】

输入:

第1行是T (T ≤200),表示测试用例数。每个测试用例的输入都由两行组成,状态A位于第1行,状态B位于第2行。保证从状态A到状态B都有有效的解决方案。

输出:

对于每个测试用例,都输出两行。第1行是“Case x :d”格式,其中x 是从1开始计算的案例号,d 是将A转换到B的操作列表的最小长度。第2行是满足约束条件的操作列表。

在这里插入图片描述

【思路分析】

本题为八数码问题,与前面八数码问题(HDU1043)不同的是,本题的终态(目标状态)不是固定不变的,而是由输入确定的。要求从初A到终态B,输出最少的步数和操作序列,而且如果最小步数相同,则输出字典序最小的一个。本题保证有解,无须可解性判断,可以采用A*、IDA算法解决,在此采用IDA算法。

【算法设计】

[1] 读入初态,用变量x 记录“X”出现的位置i ,令a [i ]=0,将其他位置减去“0”转换成数字。例如,初态为564178X23,用变量x记录“X”出现的位置6,转换之后的棋盘如下图所示。

在这里插入图片描述

[2] 读入终态,“X”出现的位置为i ,令goal[i ]=0,其他位置减去“0”转换成数字。上题(HDU1043)中目标状态数字正好等于位置下标,本题中的目标状态是根据输入数据确定的,为了方便计算启发函数,对目标状态建立一个从数字到位置下标的映射。将goal[i ]映射到位置下标i ,m [goal[i ]]=i 。

例如,终态为7568X4123,转换之后的棋盘如下图所示,m[7]=0,m [6]=2。

在这里插入图片描述

[3] 计算初态启发函数并初始化深度depth=h()。如下图所示,初始状态中数字7的位置下标为4,转换为4/3行、4%3列,即1行、1列。目标状态中数字7的映射位置下标为0,转换为0/3行、0%3列,即0行、0列。两个位置的曼哈顿距离为|1-0|+|1-0|=2。除了0(X滑块),计算当前状态和目标状态中每个位置的曼哈顿距离之和。

在这里插入图片描述

[4] 深度优先搜索,计算当前状态的启发函数h (),如果正好为0,则找到目标输入答案,返回1。如果d +t >depth,则更新mindep=min(mindep, d +t ),返回0。

[5] 沿着4个方向搜索,如果x 的新位置未出边界、不是前一个位置,则交换原位置和新位置,记录操作序列,从新位置开始深度加1,进行深度优先搜索,如果找到答案,则返回1,否则交换原位置和新位置,还原现场并回溯。

[6] 如果未找到答案,则深度为depth=mindep,继续进行迭代加深搜索。

【算法实现】

定义方向数组及操作序列,操作序列字母按字典序排序。

#include
#include
#include
using namespace std;
const int inf=0x3f3f3f3f;
const int dir[4][2]={{1,0},{0,-1},{0,1},{-1,0}};
const char str[]={'d','l','r','u'};//保证字母序
int a[9],goal[9],m[9];
int depth,mindep;
char ans[1000005];int h(){//启发函数,曼哈顿距离(行列差绝对值之和) int cost=0;for(int i=0;i<9;i++){if(a[i])cost+=abs(i/3-m[a[i]]/3)+abs(i%3-m[a[i]]%3);}return cost;
}bool dfs(int x,int d,int pre){int t=h();if(!t){printf("%d\n",d);ans[d]='\0';printf("%s\n",ans);return 1;}if(d+t>depth){mindep=min(mindep,d+t);return 0;}for(int i=0;i<4;i++){int row=x/3+dir[i][0];int col=x%3+dir[i][1];int newx=row*3+col;//转换为数字 if(row<0||row>2||col<0||col>2||newx==pre) continue;swap(a[newx],a[x]);ans[d]=str[i];if(dfs(newx,d+1,x)) return 1;swap(a[newx],a[x]);}return 0;
}void IDAstar(int x){depth=h();while(1){mindep=inf;if(dfs(x,0,-1))break;depth=mindep;}
}int main(){int T,x,cas=0;scanf("%d",&T);while(T--){scanf("%s",ans);for(int i=0;i<9;i++){if(ans[i]=='X')//大写Xx=i,a[i]=0;elsea[i]=ans[i]-'0';}scanf("%s",ans);for(int i=0;i<9;i++){if(ans[i]=='X')goal[i]=0;elsegoal[i]=ans[i]-'0';m[goal[i]]=i;//映射位置}printf("Case %d: ",++cas);IDAstar(x);}return 0;
}

在这里插入图片描述

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...