《算法入门经典》例题5-2
分析:
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所在木块堆的顶部
四种操作一一枚举的话代码会很复杂
所以用函数+函数调用来解决
首先在这题中把对木块的动作作为函数实现目标(动作就是寻找+移动+归位)
接着把对木块实际进行的操作用函数调用实现(实现了何时移动,何时归位移动几个,归位几个的具体步骤)
看一下这些操作具体是如何实现的
move a onto b:
move a over b:
pile a onto b:
pile a over b:
观察四个操作发现有且只有这两者都执行了a的归位操作,而这两个操作共同点是有move,故得到if(s1==”move”) clear_above(pa,ha);
move a onto b:
move a over b:
同理,以下两个操作执行了b的归为操作,故得到if(s2==”onto”) clear_above(pb,hb);
move a onto b:
move a onto b:
最后发现不管是如何摞动,都可以看作是将把a及上面的木块整体摞在b所在木块堆的顶部,也就有了pile_onto(pa,ha,pb);
比如move a onto b就是把a及上面的木块整体摞在b所在木块堆的顶部,只不过a所在的整体只有a本身,b所在的整体也只有b本身。
其余同理
#include <bits/stdc++.h>
using namespace std;
const int maxn = 30;
int n;//输入n个木块
vector<int> pile[maxn];
//寻找木块在哪个堆的哪一个位置,找到后以引用形式将返回给外部的pa和ha(或pb和hb)
void find_block(int a,int& p,int& h){//这里传的是引用,比如以形参p作为实参pa的别名,使其进行函数内部操作后,同时改变函数外部p的值
for(p=0;p<n;p++){
for(h=0;h<pile[p].size();h++){
if(pile[p][h]==a)return;//找到了就退出函数,同时把p,h值以引用的方式给了外部
}
}
}
//把某堆上的某木块上方的所有木块移回原位
void clear_above(int p,int h)//这里是操作第p堆的第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);
}
//把某堆上的某木块以及其上方的所有木块整体移到另一个木块上方
void pile_onto(int p,int h,int p2){
//先移动到目的地,再缩小原来的堆的区间
for(int i=h;i<pile[p].size();i++)pile[p2].push_back(pile[p][i]);
pile[p].resize(h);//此时区间是0~h-1。因为h也被挪走了。
}
//输出结果
void print(){
for(int i=0;i<n;i++){
cout<<i<<':';
for(int j=0;j<pile[i].size();j++){
cout<<' '<<pile[i][j];
}
cout<<endl;
}
}
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);
find_block(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);
}
//当不以这个格式cin>>s1>>a>>s2>>b输入时,即输入了quit,那么就退出循环,输出结果
print();
return 0;
}