2017级算法第一次上机之SkyLee在GameStop
- 题目描述
SkyLee有一天逛街的时候看到一家新开业的GameStop,里面卖各种各样的游戏。
商店里所有的游戏都按游戏名的字典序从小到大排列好了,小的在里面,大的在外面。
SkyLee想要把所有的游戏都试玩(买不起游戏只能看看),但是有些问题:
1.游戏只能从展示架的一侧拿出来
2.SkyLee只能拿1个游戏试玩
3.为了不被商店老板发现蹊跷,SkyLee把游戏光盘放回去的时候总要保证每个展示架的游戏仍然按照字典序从小到大排列(小的在里面,大的在外面)
4.SkyLee虽然没钱但是不可能偷游戏,离开时不能拿着游戏
5.SkyLee发现了两个空的展示架可以放游戏
SkyLee给摆放有游戏的那个展示架编号1,空的编号2和3。
假设SkyLee拿游戏、放游戏和试玩游戏都需要时间,现在由你来帮SkyLee提出一个最快的把所有游戏都试玩完的方案吧。
在同样快的试玩方案中,SkyLee会第一时间试玩他拿到的新游戏,然后尽量把字典序更小的游戏放在编号大的展示架上。
- 输入
多组数据
每组数据1个数n表示游戏的数量。
1≤n≤10
- 输出
对于每组数据,输出把所有游戏都试玩完的最快方案,按以下要求: 拿出游戏输出一行get game from board i,其中i是展示架的编号。 放回游戏输出一行put game to board i,其中i是展示架的编号。 试玩游戏输出一行playing。 离开商场输出一行leave。
其实就是汉诺塔问题的一个变式,首先我们来回顾一下汉诺塔问题,汉诺塔问题是一个经典的递归问题,要想把所有的碟子从A柱移动到C柱,我们只要把A柱的n-1个盘子通过C柱移动到B柱,再把最后一个盘子移动到C柱,最后把B柱上的n-1个盘子移动到C柱上即可。这样就实现了把n个盘子从A移动到C的功能。
这个题目,要注意的是
- 最终状态并不是所有盘子都在同一柱子上
- 每个盘子第一次拿取和后续拿取输出不同
因此需要两个不同的输出函数和两个不同的递归函数来处理,并且最终状态应当为最后两个盘子随意放置即可。
话不多说,AC代码如下
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<iostream>
using namespace std;
void move(char from,char to){
cout << "get game from board " << from << endl;
cout << "playing" << endl;
cout << "put game to board " << to << endl;
}
void move1(char from, char to) {
cout << "get game from board " << from << endl;
cout << "put game to board " << to << endl;
}
void hanoi1(int n, char from, char mid, char to) {
if (n == 1) {
move1(from, to);
return;
}
hanoi1(n - 1, from, to, mid);
move1(from, to);
hanoi1(n - 1, mid, from, to);
}
void hanoi(int n, char from, char mid, char to) {
if (n == 1) {
move(from, to);
return;
}
hanoi(n - 1, from, to, mid);
move(from, to);
hanoi1(n - 1, mid, from, to);
}
int main() {
//freopen("Text.txt", "r", stdin);
int n;
while (cin >> n) {
if (n > 2) {
hanoi(n - 2, '1', '3', '2');
move('1', '3');
move('1', '1');
}
else if (n == 2) {
move('1', '2');
move('1', '3');
}
else
move('1', '3');
cout << "leave" << endl;
}
return 0;
}
其中,move函数是指第一次移动时候需要进行的操作,move1函数是指第二次移动时候需要进行的操作,我们把顶上n-2个盘子移动到B柱的过程中,先要把n-3个盘子从A第一次移动到C,之后把剩下的盘子移动到B后,再第二次把n-3个盘子从C调回B,在这次调回时是不需要再play的因为已经play过了,所以调用的是move1函数。