原题链接: UVa-120
参考博客:
题目大意:
有N张正在锅里的一叠煎饼,每张都有一个数字,代表其直径大小。厨师每次可以选择一个数k,把从锅底开始数第k张上面的煎饼全部翻过来,即原来在上面的煎饼现在到了下面。要求设计一种方法使得所有煎饼按照从小到大排序(最上面的煎饼最小)。
解题思路:
题目如果看懂,知道怎么操纵的话这道题很容易实现。关键就是要搞懂怎么操作的。整体思路就是将最大值放到最右边(底部),然后每次都将一个没有归位的最大值放到其相应位置,形成升序。
具体操作方法就是,对每个未确定是否归位的最大值进行如下操作:
如果当前最大值已经在正确的位置上,不进行任何操作。
如果当前最大值在最左边(顶部),则从它开始到最左边进行flip,将其颠倒到最右端(底部)
如果当前最大值不在左边(顶部),先将颠倒到最左边,再从它该在的位置一直到顶端颠倒。
遇到问题:
一开始没有读英文的题目,直接看的样例的输入和输出,试了半天也没搞明白,输出的数字到底是煎饼上数字还是层数,还有到底是向左颠倒还是向右颠倒。弄得很懵逼。看了参考博客之后明白。
另外,uDebug上给的数据答案是错的,不知道为什么还有那么多投票。
代码:
#include<iostream>
#include<sstream>
#include<string>
using namespace std;
void solve(int n);
void flip(int n);
int find_max(int n);
const int MAXN = 30 + 10;
const int INF = 0x7fffffff;
int pc[MAXN];
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
string s;
while (getline(cin, s)) {
stringstream ss(s);
int cnt = 0;
while (ss >> pc[cnt++]);
cout << s << endl;
solve(cnt - 1);
cout << "0\n";
}
return 0;
}
void solve(int n)
{
for (int i = n - 1; i >= 0; i--) {//对每个煎饼都进行如下操作
int max = find_max(i);//寻找pc[0..i]最大值
if (pc[i] != max) {//如果最大值已经在最底部,不用进行任何操作,不在的话进行如下操作
if (pc[0] != max){ //pc[0..i]中的最大值既不在底部也不在顶部
int j;
for (j= i; j >= 0; j--) if (pc[j] == max) break;//先找到最大值所在的位置
flip(j); cout << n - j << " "; //反转到顶部
}
flip(i); cout << n - i << " "; //最大值在在最顶部则可以直接反转
}
}
}
//反转pc[0]...pc[n]
void flip(int n)
{
int mid = (n + 1) / 2;
for (int i = 0, j = n; i < mid; i++, j--) {
int t = pc[i]; pc[i] = pc[j]; pc[j] = t;
}
}
//找到pc[0..n]中最大值
int find_max(int n)
{
int max = -INF;
for (int i = 0; i <= n; i++) max = max > pc[i] ? max : pc[i];
return max;
}