【代码超详解】UVA 120 Stacks of Flapjacks 烙饼堆(0 ms)

一、题目描述
已知有一些半径(正整数)小于 100 的煎饼,数量不超过 30 个。
输入包含多组数据,每组数据只有一行,为每个煎饼的半径,两个半径之间用空格隔开,顺序是从锅顶到锅底。要求在输出的第一行照抄输入内容,第二行开始输出全部翻转的位置,两个位置之间用空格隔开,并以 0 结尾(0 之前也要空格)。
要求在翻转若干次之后能使煎饼的半径从上到下逐渐加大。底部的饼的位置记为 1 。翻转某一位置的饼会连同其上部的煎饼一同被翻转。
示例:

翻转第 3 张烙饼,可以将烙饼的排序由第一列变成第二列。再翻转第 1 张就可以变成第三列。

二、算法分析说明与代码编写指导
因为每组样例的煎饼数量未知,所以直接用 scanf 读入数值无法得知是否输入结束。这里先用 gets_s 来读入整行,然后再分离出各个半径。也可以用循环和 getchar 配合。
较新的 C++ 标准已经弃用 gets 函数。如果 OJ 无法识别 gets_s ,应该改回 gets ,并删去读入字符数量限制,只留下字符数组作为参数。在本题中就是将 13 行的 gets_s(c, 120); 改成 gets© 。
由于数据规模不大(n ≤ 30),所以可以直接模拟整个过程。
将每个煎饼的半径读入数组 a ,然后复制到数组 b ,排序。b 是最终目标。
从 b 数组的末端开始向前读取每一个半径(也就是先读大的再读小的),然后在 a 中查找其位置,如果与 b 中对应的位置不符,就先将数组 a 中这个位置及之前的部分翻转,然后再将 a 中对应目标位置的数及其之前的数再翻转,就将这个半径放到了目标位置。对于剩下的半径也是这样处理。
通过 algorithm 头文件中的 reverse 函数可以方便地完成翻转。如果翻转的位置是数组开头,那么就相当于没翻转,这一步不能输出(题目里没说)。
例如:
5 1 2 3 4 ,要变成 1 2 3 4 5 。
5 在开头而不是结尾,要翻转 5 及之前的数(这一步不输出)。然后 5 要放到最后,就将数组开头到最后翻转一遍,就变成 4 3 2 1 5 。
4 在开头而不是结尾,要翻转 4 及之前的数(这一步不输出)。4 要放到倒数第二的位置,所以翻转倒数第二位及之前的数值,就变成 1 2 3 4 5 。排序完毕。
这里用 a2 代表数组 a 结尾的下一个地址,p 代表输入的煎饼总数,q 代表要查找的煎饼半径在数组 a (原数据)中的偏移量。

三、AC 代码(0 ms)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#pragma warning(disable:4996)
char a[31], b[31], * a2 = a, c[121]; long long p = 0, q; unsigned long long l;
inline bool sorted() {
	for (char i = 0; i < p; ++i)if (a[i] != b[i])return false;
	return true;
}
int main() {
	for (;;) {
		gets_s(c, 120); if (feof(stdin))return 0;
		l = strlen(c); fill(a, a2, 0); p = 0;
		for (unsigned long long i = 0; i < l; ++i) {
			if (c[i] == ' ') { ++p; }
			else { a[p] = a[p] * 10 + c[i] - 48; }
		}
		++p; a2 = a + p; copy(a, a2, b); sort(b, b + p); printf("%hhd", a[0]); for (long long i = 1; i < p; ++i) { printf(" %hhd", a[i]); }putchar('\n');
		for (long long i = p - 1; sorted() == false; --i) {
			q = find(a, a2, b[i]) - a; if (q != i) {
				reverse(a, a + q + 1); if (q != 0)printf("%lld ", p - q); reverse(a, a + i + 1); if (i != 0)printf("%lld ", p - i);
				//putchar('\n'); for (long long j = 0; j < p; ++j) { printf("%hhd ", a[j]); }putchar('\n');
			}
		}
		puts("0");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值