积木移动题目分析及解题思路——木块问题(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

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

相关推荐
努力努力再努力wz6 分钟前
【内存管理与高并发内存池系列】从 mmap 到 malloc:文件映射、匿名映射与 glibc 内存分配机制详解
linux·c语言·数据结构·数据库·c++·qt·链表
八解毒剂26 分钟前
数据结构-平衡二叉树——对二叉搜索树的优化
数据结构·c++·算法
运行时记录1 小时前
别再手动写提示词了 — SkillOpt 让技能文档自己进化
算法
起床困难户5751 小时前
条款20:协助完成返回值优化
c++
啦啦啦啦啦zzzz1 小时前
算法总结(二分查找、双指针)
c++·算法
qq_8573058191 小时前
python语法
开发语言·python·算法
DXM05212 小时前
第9期|从机器学习到深度学习:AI遥感解译的进化逻辑
人工智能·算法·计算机视觉
小蒋学算法2 小时前
算法-阶乘函数后K个零
算法
weixin_307779132 小时前
智能模拟数据生成平台:生成式AI合成数据技术重塑开发测试效能
人工智能·测试工具·算法·测试用例
不负岁月无痕2 小时前
C++ 模板核心内容与高频面试题汇总
java·开发语言·c++