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


    【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')//大写X
    				x=i,a[i]=0;
    			else
    				a[i]=ans[i]-'0';
    		}
    		scanf("%s",ans);
    		for(int i=0;i<9;i++){
    			if(ans[i]=='X')
    				goal[i]=0;
    			else
    				goal[i]=ans[i]-'0';
    			m[goal[i]]=i;//映射位置
    		}
    		printf("Case %d: ",++cas);
    		IDAstar(x);
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    在这里插入图片描述

  • 相关阅读:
    Junit单元测试框架详解
    算法复杂度分析笔记
    使用 MRKL 系统跨越神经符号鸿沟
    当前JavaEE初阶的阶段知识总结
    十五、红外遥控器
    大数据-玩转数据-双流JOIN
    本地浏览器打开远程服务器上的Jupyter Notebook/Lab以及常见问题&设置
    www.7seasnft.com、数字藏品、总结
    【Python】学生管理系统——详细解释+代码+详细注释(课设必过)
    Python Spider学习笔记(一):爬取B站视频基本信息
  • 原文地址:https://blog.csdn.net/weixin_44226181/article/details/127842241