积木移动题目分析及解题思路——木块问题(1)

积木移动题目分析及解题思路------木块问题(1)

  • 一、题目描述
  • Input
  • Output
  • 二、题目分析
    • [2.1 难度分析](#2.1 难度分析)
    • [2.2 C语言识别策略](#2.2 C语言识别策略)
      • [2.2.1 数据输入方式](#2.2.1 数据输入方式)
      • [2.2.2 数组第二维下标识别](#2.2.2 数组第二维下标识别)
    • [2.3 积木操作](#2.3 积木操作)
  • 三、解题思路
    • [3.1 基本思路](#3.1 基本思路)
    • [3.2 ASCII码值测试](#3.2 ASCII码值测试)

今天在看到《算法竞赛入门经典》例题5-2 木块问题(The Blocks ProblemUva 101),书中的题目描述和Uva网站上的要求还是有一些细微差异的。我想在看书本答案之前自己做做这道题,考虑到测试方便,本文题目描述完全基于原题网站。

Uva网站题目链接:
Problem ID: 101:The Blocks Problem

点击箭头处可浏览英文题目描述。

一、题目描述

木块问题(The Blocks Problem,Uva 101):

从左到右有n个木块,编号为0~n-1,要求模拟以下4种操作(下面的a和b都是木块编号)。

move a onto b:把a和b上方的木块全部归位,然后把a摞在b上面。

move a over b:把a上方的木块全部归位,然后把a放在b所在木块堆的顶部。

pile a onto b:把b上方的木块全部归位,然后把a及上面的木块整体摞在b上面。

pile a over b:把a及上面的木块整体摞在b所在木块堆的顶部。

遇到quit时终止一组数据。当输入的a和b相等或在同一堆时,指令是非法指令,应当忽略(不做任何移动操作)。

Input

第1行输入整数 n n n,表示积木数量 0 < n < 25 0 \lt n \lt 25 0<n<25。

从第2行开始,每行输入一个积木操作命令,直到遇到quit命令为止。

Output

输出每个位置的积木列表,位置编号 i i i满足 0 ≤ i < n 0 \le i \lt n 0≤i<n

每行由"位置编号+冒号+空格+积木列表"构成,积木列表中各个积木编号中间用空格隔开,最后一个积木编号后不能有空格。

每个块位置输出一行,即总共输出n行。

样例输入:

复制代码
10
move 9 onto 1
move 8 over 1
move 7 over 1
move 6 over 1
pile 8 over 6
pile 8 over 5
move 2 over 1
move 4 over 9
quit

样例输出:

复制代码
0: 0
1: 1 9 2 4
2:
3: 3
4:
5: 5 8 7 6
6:
7:
8:
9:

二、题目分析

这个问题算法上没什么难度,就是按人家要求把积木块移来移去就行了。

最直接的想法就是搞个二维数组,第一维表示积木的位置,第二维表示位置上有哪些积木。

2.1 难度分析

题目的难度主要在于识别:

  • 识别输入内容。要识别move 9 onto 1这样的输入属于哪种操作类型,然后才能按要求操作对应的积木。对于C语言来说,那无非就是scanf、getchar、fgets;如果是C++,那就是cin、getline,但是这两个东东俺不太熟,还是想先用C语言搞一搞。
  • 数组第二维下标识别。把积木移到某个位置,都要找到放到对应位置的第几层(也就是第二维的下标)。如果是用普通数组那需要自己去识别,但是如果用C++的vector,那就美美不用管它了。

2.2 C语言识别策略

C++可以使用string、vector,两大难点都很容易解决,不用详细讨论,这里只讨论C语言的识别策略。

2.2.1 数据输入方式

用scanf输入的好处是可以自然地以"空格"为界把同一行分为四个部分,清清楚楚,然后就分头处理各个串就行了。但是这需要用到字符串比较函数,说实话这玩艺我还没用过,不过应该很简单,查一下就行了。

如果用getchar呢,那就要一个字符一个字符去识别,读取一次就完事了,貌似也不是不可以。

用fgets整行输入是没什么意义的,因为还得从头一个字符一个字符的去分析,那还不如直接用getchar。

2.2.2 数组第二维下标识别

如果就用C语言的普通数组,我想到两种处理方法:

(1)预设不可能值法。就是把数组所有元素的值预先赋一个不可能取值,比如"-1",这样第一个"-1"就是数组的末尾。如果是动态数组那就简单了。

(2)存储末尾下标法。更简单的方法,就是用数组中某个固定位置(比如第一个或最后一个位置)的元素实时记录数组的最后一个积木的下一个位置,也就是第一个空位。我打算用这个方法。

2.3 积木操作

积木操作类型一种有4种:

  • move a onto b:把a和b上方的木块全部归位,然后把a摞在b上面。
  • move a over b:把a上方的木块全部归位,然后把a放在b所在木块堆的顶部。
  • pile a onto b:把b上方的木块全部归位,然后把a及上面的木块整体摞在b上面。
  • pile a over b:把a及上面的木块整体摞在b所在木块堆的顶部。

总结下来,实际上只有两种操作:

  • 归位:把a或b上方的积木放回到原来的位置。
  • 移动:把a及上面的木块直接摞到b所在位置处。

可以把这两种操作写成两个函数ret(x),move(a, b)。

归位函数我本来想用return(x),但是return是关键字,只好搞个阉割版。

三、解题思路

我决定先用getchar操练一下,一次读入,搞定识别,不用标准库的其他任何字符串函数。

3.1 基本思路

getchar函数的功能是一次读入一个字符,所以就要每读一个字符,识别一次。读完一行的所有字符,就要识别出操作类型,积木a、b的编号。

识别过程中,一旦读到move就调用ret(a),一旦读到onto就调用ret(b),读到pile、over不用作任何处理。

最后,直接调用move(a, b)就OK了。

c 复制代码
int main(){
	while(flag){
		int c=getchar();
		if(回车){
			识别命令;
			执行命令:ret(x);
			执行命令:move(a, b);
		}
	}
}

3.2 ASCII码值测试

忘了数学、字母的ASCII码值了,写了个程序测试了一下。

c 复制代码
#include<stdio.h>

int main(){
    int c;
    c=getchar();
    printf("%d\n", c);
    return 0;
}

由程序得出以下字符的ASCII码值:

  • 0:48
  • a:97
  • 回车:10
  • 空格:32

天不早了,今天就先叨叨到这里,下集再写具体的代码。

相关推荐
我不是懒洋洋2 小时前
大语言模型(LLM)入门:从Transformer到ChatGPT
c语言·开发语言·c++
研究点啥好呢2 小时前
小鹏汽车 机器人运动规划算法工程师 面试题精选:10道高频考题+答案解析
算法·机器人·汽车
小许同学记录成长2 小时前
原始 IQ 数据时频图生成
python·算法
小小测试开发2 小时前
OpenAI 模型攻克离散几何 80 年难题:Erdős 单位距离猜想被 AI 证明
人工智能·算法·机器学习
moonsims2 小时前
从“传感器融合”升级为“多机器人约束融合系统”-Factor Graph 多约束融合
人工智能·算法
Dfreedom.2 小时前
模型剪枝完全指南:从理论到实践,打造高效深度学习模型
人工智能·算法·机器学习·剪枝·模型加速
BestOrNothing_20152 小时前
C++零基础到工程实战(5.2.4):指针与引用在函数传参、返回值与效率优化中的应用
c++·指针·引用·const·函数参数
L_09072 小时前
【C++】面向对象三大特性之多态
开发语言·c++
几司3 小时前
OpenISP 模块拆解 · 第11讲:非局部均值降噪 (NLM)
人工智能·算法·均值算法·isp