题目
(侵删)
给定一叠煎饼,你要写一个程序计算出如何才能使这叠煎饼自底向上由大至小的排列。给定煎饼的半径作为其尺寸,一叠煎饼的大小各不相同。
为煎饼叠排序是通过一些列的“翻转”动作来完成的。一个翻转动作就是将一个小铲插到煎饼叠中的某两个煎饼之间,然后将小铲上面的所有煎饼翻转(倒转小铲上面的子栈)。每个翻转动作由其开始的位置给出,即小铲上面子栈中最底下一个煎饼的编号。整叠煎饼中最下面一个的位置为1,n个煎饼的叠中最上面一个的位置为n。
一个煎饼叠由一组表示其中各煎饼直径的数构成,它们排列的顺序就是给出的这些数的顺序。
比如下面三个煎饼叠(煎饼8是左边一叠的最上面的一个)
8 7 2
4 6 5
6 4 8
7 8 4
5 5 6
2 2 7
左边一叠可以通过翻转第3个煎饼变成中间一叠的顺序。中间一叠可以通过翻转第1个煎饼变成右边一叠的顺序。
The Input
输入包括一系列煎饼叠。每叠都由1到30个煎饼组成,并且每个煎饼的直径都在 1到100之间。输入由EOF结束。每叠煎饼独占一行,最上面的在行首,最下面的在行尾,各煎饼中间由空格隔开。
The Output
对应于每叠煎饼数据,必须在第一行输出原叠的内容,接下来输出一组翻转动作的序列,使得这一叠煎饼自底向上由大至小的排列。输出的每一组翻转动作序列都要由0来结束(表示不再进行翻转)。一旦一叠煎饼已经排好序,就不能再进行任何翻转。
思路
0.好一个直接构造解。。让我写了半个月。。
1.本题策略:每次找到最大的煎饼,将其翻到顶部,在翻到底部即可。底部累积,所以上面翻来翻去不会影响累积的底部。
2.本题值得学习的输入方法:不给数量的单行输入
代码
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 1000;
int n, A[maxn];
vector<int> ans;
void swapqu(int x, int y) { // 此处为闭区间
while (x < y) {
swap(A[x], A[y]);
x++;
y--;
}
}
void solve(int x, int y) {
if (x<y) {
int maxp = x;
for (int i = x; i<y; i++)
if (A[maxp] < A[i])
maxp = i;
if (maxp != y - 1) {
if (maxp != x) {
swapqu(x, maxp);
ans.push_back(abs(n - maxp));
}
swapqu(x, y - 1);
ans.push_back(abs(n-y+1));
}
solve(x, y - 1);
}
}
int main() {
char c,tmp[maxn];
int a,p=0;
while (scanf("%d%c",&a,&c) != EOF) {
A[p] = a;
if (c != '\n') {
p++;
continue;
}
else {
p++;
for (int i = 0; i < p; i++)
printf("%d ", A[i]);
printf("\n");
n = p;
p = 0;
}
ans.clear();
// A数组序号越小,越在上面
solve(0, n);
ans.push_back(0);
int i = 0;
for (vector<int>::iterator iter = ans.begin(); iter != ans.end(); ++iter) {
if (!i) printf("%d", *iter);
else printf(" %d", *iter);
i++;
}
printf("\n");
}
return 0;
}