煎饼堆 题解

煎饼堆(flapjacks.cpp)
【问题描述】
在架子上烤一堆完美的煎饼是一件技巧性很高的工作,因为无论你有多努力,烤出的饼的直径都会各不相同。为了整洁,你可以将所有的饼按大小排序,使得每个饼下面所有饼的直径都比它大。
为这堆饼排序是通过一系列的“翻转(flip)”操作来实现的。有一把铲子可以用来插在两张饼之间,并将铲子之上的所有饼翻转过来。每次翻转操作用最下面一张被翻转的饼在整堆饼的位置来描述。如果一共有n张饼,最底部的饼位置为1,最上面的饼位置为n。
一堆饼由从上到下各张煎饼的直径来表示。例如,下面的3堆饼,在最左边的一堆中,最上面的一张直径为8:
8 7 2
4 6 5
6 4 8
7 8 4
5 5 6
2 2 7
最左边一堆可以通过操作flip(3)变成中间的一堆,再通过操作flip(1)变成右边的一堆。
【输入格式】
输入包含了若干堆饼的数据。每堆饼的张数在1到30 之间,并且每个饼的直径是1到100之间的整数。输入用文件结束符终止。每堆饼的数据都在单独一行中给出,每行的第一个数代表最上面的那张饼的直径,最后一个数代表最下面那张饼的直径。相邻两个数被一个空格隔开。
【输出格式】
对于每一堆饼,你的程序要先用单独一行输出原始的顺序,然后在下一行输出能够让最大的饼在最下面,最小的饼在最上面的翻转操作序列。翻转序列应该以0结束,表示不必再进行多余的翻转。当一堆饼被排列好以后,不要再进行多余的动作。
【时限,空间要求】
1秒,256M。
【输入输出样例】
flapjacks .in
flapjacks .out
1 2 3 4 5
5 4 3 2 1
5 1 2 3 4
1 2 3 4 5
0
5 4 3 2 1
1 0
5 1 2 3 4
1 2 0

//  
// 先将数据排序,然后根据排序后的结果将原来的序列进行相应操作变成最终的序列。在排序时,由于可能有  
// 两个饼具有相同的直径,故需要记录数据的序号,恢复的方法是找到当前尚未排序的X,先将其翻转到顶端,  
// 然后再翻转到其在最终排序后的位置。  
      
#include <iostream>  
#include <sstream>  
#include <algorithm>  
#include <cstdio> 
      
using namespace std;  
      
#define MAXSIZE 30  
      
struct pancake  
{  
    int diameter;  
    int index;  
};  
      
pancake pancakes[MAXSIZE];  
pancake original[MAXSIZE];  
      
bool cmp(pancake x, pancake y)  
{  
    return x.diameter < y.diameter;  
}  
      
void flip(int pos, int size)  
{  
    pancake tmp;  
    int i = 0, j = size - pos;  
    for (; i < j; i++, j--)  
        if (original[i].diameter != original[j].diameter)  
        {  
            tmp = original[i];  
            original[i] = original[j];  
            original[j] = tmp;  
        }  
}  
      
int main()  
{  
    
	string line;  
	freopen("flapjacks.in","r",stdin);
	freopen("flapjacks.out","w",stdout);
    while (getline(cin, line))  
    {  
        // 回显。  
        cout << line << endl;  
      
        // 读入数据。  
        int capacity = 0;  
        istringstream iss(line);  
        while (iss >> pancakes[capacity].diameter)  
        {  
            pancakes[capacity].index = capacity;  
            original[capacity] = pancakes[capacity];  
            capacity++;  
        }  
      
        // 排序。  
        sort(pancakes, pancakes + capacity, cmp);  
      
        // 执行翻转操作,若第 i 大元素未在第i位上,则先找到其序号,然后  
        // 先将其翻转到顶端,然后再翻转到位置i。  
        for (int i = capacity - 1; i >= 0; i--)  
        {  
            // 在当前序列中找到该元素。  
            // 假如数原来的序号与当前的序号不等,需要翻转操作。  
            int marker;  
            for (int j = 0; j < capacity; j++)  
                if (original[j].index == pancakes[i].index)  
                {  
                    marker = j;  
                    break;  
                }  
      
            if (marker != i)  
            {  
                if (marker != 0)  
                {  
                    cout << (capacity - marker) << " ";  
                    flip(capacity - marker, capacity);  
                }  
  
                cout << (capacity - i) << " ";  
                flip(capacity - i, capacity);  
            }  
        }  
      
        cout << "0" << endl;  
    }  
    
	fclose(stdin);
	fclose(stdout);  
    return 0;  
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值