算法竞赛入门经典(第二版) | 例题5-2 木块问题 (紫皮书牛啤!)(UVa101,The Blocks Problem)

大意:

输入n,代表n个木块,输入最多n种操作类型,按类型对木块进行操作,读入quit结束

输入输出格式:

1、move a onto b:将a和b所在上方的方块先归位,再将a移到b所在柱子
2、move a over b:仅将a所在上方的方块先归位,再将a移到b所在柱子
3、pile a onto b:将b所在上方的方块先归位,再将a及其上方的所有方块移到b所在柱子
4、pile a over b:无需归位,直接将a及其上方的所有方块移到b所在柱子
5、quit:结束,打印输出
6、无效指令:命令中a和b在同一柱子,直接忽略即可

分析:

本题思路不难想,但若想写出简洁的代码,就需要动一番脑筋了,如何提高代码的复用性呢?我们先归纳出重要步骤:
  1、找a和b块
  2、若为move或onto,则a或b块归位
  3、将a的方块移动到b上,
这时我们不难发现:
找a块和b块的代码是相似的,因此可以写一个函数复用;同理,将a块归位,与将b块归位也是类似的,同样写一个函数复用,这样代码就简洁了不少。当然,print()函数也是不可或缺的,调试神器啊!详情见第34行代码。


题目(提交)链接→UVa-101

没使用过该网站的同学请猛戳这里→vJudge教程


代码:

#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;

const int maxn = 30;
int n;
vector<int> pile[maxn];									//因为木块的长度不定,所以适合用vector保存

//找木块的pile和height,以引用的形式返回(配合void)
void find_block(int a, int& p, int& h) {
	for(p = 0; p < n; p++) 
		for(h = 0; h < pile[p].size(); h++)
			if(pile[p][h] == a) return;					//要有自信好吧!这个复杂度也是o(n3) 
} 

//把第p堆高度为h的木块上方的所有木块移回原位。
void clear_above(int p, int h) {						//p代表行,h代表列
	for(int i = h+1; i < pile[p].size(); i++) {
		int b = pile[p][i];
		pile[b].push_back(b);
	} 
	pile[p].resize(h+1);								//pile只应保留下标0~h的元素,采用这种方法,就不需要用pop一个一个弹出了。 
}

//把第p堆高度为h及其上方的木块整体移动到p2堆的顶部
void pile_onto(int p, int h, int p2) {
	for(int i = h; i < pile[p].size(); i++) 			//从块1所在行往上截取, 
		pile[p2].push_back(pile[p][i]);					//从块2所在列往上堆填 
	pile[p].resize(h);
} 

//调试神奇print()重出江湖
void print() {
	for(int i = 0; i < n; i++) {
		printf("%d:", i);
		for(int j = 0; j < pile[i].size(); j++) print(" %d", pile[i][j]);
		printf("\n");
	}
} 
 
 
int main()
{
	int a, b;
	cin >> n;
	string s1, s2;
	for(int i = 0; i < n; i++) pile[i].push_back(i);	//压入,数据等于下角标 
	while(cin >> s1 >> a >> s2 >> b) {
		int pa, pb, ha, hb;
		find_block(a, pa, ha); 							//a是待移动木块角标,pa是所在行,ha是所在列
		find_block(b, pb, hb);							//b是最终位置角标,pb是所在行 , hb是所在列
		if(pa = pb) continue;							//若所在行相同,则为无效移动
		if(s2 == "onto") clear_above(pb, hb); 
		if(s1 == "move") clear_above(pa, ha); 
		pile_onto(pa, ha, pb);						
	} 
	
	return 0;
 }  

收获:

1、二维数组vector,行固定,列不固定
2、提取关键字:找a和b块,归位,将a的方块移动到b上,都可以各提取出一个函数,进行函数复用。
3、采用自顶向下的编写方法,函数复用技巧,调试技巧。
4、resize代替pop

发布了73 篇原创文章 · 获赞 61 · 访问量 4775

猜你喜欢

转载自blog.csdn.net/weixin_43899069/article/details/104474970
今日推荐