大意:
输入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