小强有 3 个箱子 A,B,C 用来装书,所有的书(一共n本)都按序号由小到大的顺序堆在 A上,现在他想把所有的书全都放到 C 里面去。每次他从 A 书架拿 a 本书(不够就全拿完)到 B,A 箱子翻转,然后从 B 拿 b 本书(不够就全拿完)到 C,B 箱子翻转。然后重复操作,直到所有书都到了 C,求最后的C 里面书的顺序,详细见样例。
输入描述:
输入由多组数据构成,每组数据占一行,3 个数,n(1<=n<=10^5),a(1<=a<=10^9) , b(1<=b<=10^9),含义见题目表述。以文件结尾。
输出描述:
每组数据输出一行,首先输出数据组数,然后输出 n 个数,C 中书的排列。
输入样例:
4 2 1
输出样例
Case 1: 1 4 2 3
Hint
初始状态A:4321 B: 空 C:空
第一次: A->B A:21 B:34 C: 空
A 翻转 A:12 B:34 C: 空
B->C A:12 B: 4 C: 3
B 翻转 A:12 B:4 C: 3
第二次: A->B A:空 B:214 C:3
A 翻转 A:空 B:214 C:3
B->C A:空 B:14 C:23
B 翻转 A:空 B:41 C:23
第三次: B->C A:空 B:1 C:423
B 翻转 A:空 B:1 C:423
第四次: B->C A:空 B:空 C:1423
思路:这道题用双向链表来做就再适合不过了,因为A和B都有翻转操作,而双向链表可以从两个方向遍历链表元素,所以当翻转之后就相当于从另一个方向取链表元素。最终,用两个双向链表代表A和B,用一个栈代表C,一直模拟题目操作,当A和B都为空的时候,输出栈C的值即可。
代码:
#include<iostream>
#include<list>
#include<stack>
using namespace std;
int main()
{
int n, a, b, n_case = 0;
while(cin >> n)
{
n_case++;
cin >> a >> b;
list<int> a_list;//存A的元素
list<int> b_list;//存B的元素
stack<int> s;//存C的元素
for(int i = 1; i <= n; i++)
a_list.push_front(i);//先用1-n装满A
int count = 1;
while(!(a_list.empty() && b_list.empty()))
{
int a_tmp = a;
int b_tmp = b;
if(count % 2 == 1)//奇数次操作的时候从链表的头部front取元素
{
while((!a_list.empty()) && a_tmp--)
{
b_list.push_front(a_list.front());//取A的前a元素
a_list.pop_front();
}
while((!b_list.empty()) && b_tmp--)
{
s.push(b_list.front());//取B的前b元素
b_list.pop_front();
}
}
else//偶数次操作的时候从尾部取元素
{
while((!a_list.empty()) && a_tmp--)
{
b_list.push_back(a_list.back());
a_list.pop_back();
}
while((!b_list.empty()) && b_tmp--)
{
s.push(b_list.back());
b_list.pop_back();
}
}
count++;
}
cout << "Case " << n_case << ":";
while(!s.empty())
{
cout << ' ' << s.top();
s.pop();
}
cout << endl;
}
return 0;
}