题目:给你n个方块,有四种操作:
1.move a onto b,把a和b上面的方块都放回原来位置,然后把a放到b上面;
2.move a over b,把a上面的放回原处,然后把a放在b所在的方块堆的上面;
3.pile a onto b,把b上面的放回原来位置,然后把a和a上面的方块整体放到b上面;
4.pile a over b,把a和a上面的方块整体放到b所在堆的上面。
分析:模拟,数据结构。观察操作,如果是move就是先把a上面的还原,如果是onto就是先把b上面的还原。
然后,就是移动一堆到另一堆的上面(单个也认为是一堆)。所以设置两个基础操作:
1.将a上面的还原init_pos(a);
2.将a和上面的(可以没有上面的)放到b上面pile_over(a, b)。
那么上述的四组操作就变成下面了:
1.move a onto b,init_pos(a);init_pos(b);pile_over(a, b);
2.move a over b,init_pos(a);pile_over(a, b);
3.pile a onto b,init_pos(b);pile_over(a, b);
4.pile a over b,pile_over(a, b)。
利用两个操作轻松解决。具体实现时设置一个place数组记录每个编号的方块对应的堆。
摘抄出处:http://blog.youkuaiyun.com/mobius_strip/article/details/12765319
再次,膜拜大神;(将模拟问题拆分为最基础的几个子问题,封装成为函数,减少代码量,同时思路更加清晰);
#include <iostream>
#include <stack>
#include <cstdio>
using namespace std;
stack<int> s[25];
int place[25]; //存放位置;
stack<int> s_t; //临时用来转换的堆;
void init_pos(int a){
int p = place[a];
while(!s[p].empty()){
int v = s[p].top();
if(v == a)
break;
s[v].push(v);
place[v] = v;
s[p].pop();
}
}
void pile_over(int a, int b){
int p_a = place[a];
int p_b = place[b];
while(!s[p_a].empty()){
int v = s[p_a].top();
if(v == a)
break;
s_t.push(v);
s[p_a].pop();
}
s_t.push(a);
s[p_a].pop();
while(!s_t.empty()){
int v = s_t.top();
s[p_b].push(v);
place[v] = p_b;
s_t.pop();
}
}
int main()
{
int n;
char oper[5], type[5];
int a, b;
while(cin >> n){
for(int i = 0; i < n; ++i){
s[i].push(i);
place[i] = i;
}
while(scanf("%s", oper)){
if(oper[0] == 'q')
break;
scanf("%d%s%d", &a, type, &b);
if(place[a] == place[b]) //b在a之上,不处理;
continue;
if(oper[0] == 'm') // 如果是move,将a之上的所有元素放回初始位置;
init_pos(a);
if(type[1] == 'n') // 如果是onto,将b之上的所有元素放回初始位置;
init_pos(b);
pile_over(a, b);
}
int s_k[25];
for(int i = 0; i < n; ++i){
cout << i << ':';
int cnt = 0;
while(!s[i].empty()){
s_k[cnt++] = s[i].top();
s[i].pop();
}
for(int j = cnt-1; j >= 0; --j){
cout << ' ' << s_k[j];
}
cout << endl;
}
}
}