Stacks of Flapjacks(翻煎饼) UVA - 120 (贪心 排序)
堆栈和队列通常被认为是数据结构的面包和黄油,可用于体系结构、解析,操作系统和离散事件模拟。堆栈在形式语言理论中也很重要。
现在的问题涉及黄油和煎饼(而不是面包),同时还有一个根据唯一但完整的规则来翻煎饼的服务器。
给你一栈的煎饼,请你编写一个程序用于指示这个栈如何被排序以使得最大的煎饼在最下面而最小的煎饼在最上面。
煎饼的直径将被给出。
栈中的所有煎饼的直径都不一样。
对栈排序是通过一系列"翻转"来完成的。
一次翻转的意思是:在两个煎饼之间插入铲子,然后将铲子上面的一堆煎饼整体翻过来。也就是指定一个位置,其上的子栈整体翻转。
翻转的位置将会被给出。
位置是这样定义的:栈底编号为1,栈顶编号为n
一个栈的煎饼的给出方式,是从上到下给出煎饼的直径。
举例来说,这是三个栈,左边的栈的最上面的煎饼直径为8
8 7 2
4 6 5
6 4 8
7 8 4
5 5 6
2 2 7
左侧栈,可在位置3(即直径7)处翻转,得到中间的那个栈,而中间那个栈可在位置1(即直径2)处翻转,得到右侧的栈。
Input
输入由多个煎饼栈组成。每个栈有1到30个煎饼,每个煎饼的直径在1-100之间。以文档结束为输入结束。每个栈,独占一行,从左到右依次代表从栈顶到栈底的煎饼的直径,空格隔开。
Output
对于每个煎饼栈,输出首先应原样将栈的数据打印成一行。
随后的一行是翻转位置的次序,空格隔开,以0结束。(结束的目标是最大直径在最下面,最小直径在最上面)。
Examples
Sample Input
1 2 3 4 5
5 4 3 2 1
5 1 2 3 4
Sample Output
1 2 3 4 5
0
5 4 3 2 1
1 0
5 1 2 3 4
1 2 0
题意:
题解:
一串序列从左到右依次是栈顶到栈底, 首先仔细理解一下翻煎饼的方式, 在某一为止插入后, 栈顶到该位置的所有元素依次反转, 确实有点像翻煎饼哈, 不妨试想一下~
这里我们思考一下排序的逻辑, 对于一个数, 如果它不在指定位置(排序后应在的位置), 我们先将它翻转到开头, 再将它翻转到指定位置, 就实现了一次排序, 有点类似基础的插入排序.
注意细节, 详细内容见代码~
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const int inf = 1<<30;
const LL maxn = 33;
int stk[maxn], len;
int findi(int n){
//返回n在stk中的下标
for(int i = 1; i <= len; i++)
if(stk[i]==n) return i;
}
void flip(int p){
//模拟翻转操作
cout << len-p+1 << ' ';
for(int i = 1, j = p; i < j; i++, j--)
swap(stk[i], stk[j]);
//for(int i = 1; i <= len; i++) cout << stk[i] << ' '; cout << endl;
}
void solve(){
int tmp[maxn];
memcpy(tmp, stk, sizeof(stk));
sort(tmp+1, tmp+1+len);
for(int i = len; i > 0; i--){
int curI = findi(tmp[i]); //当前下标
if(curI!=i){
//先翻至开头, 再翻至目标位置
if(curI!=1) flip(curI);
if(findi(tmp[i])!=i) flip(i);
}
}
}
int main()
{
while(cin >> stk[1]){
for(len = 2; getchar()!='\n' && cin >> stk[len]; len++);
len--;
for(int i = 1; i <= len; i++)
cout << stk[i] << ' ';
cout << endl;
solve();
cout << '0' << endl;
}
return 0;//
}