孩子们,我想你们了。今天带来的题目有点难,情景有点复杂,但是我相信你们在看完我的思路和代码后一定会有收获。
填充立方体(10分)
题目描述
期中考试小南设计的填数游戏非常有意思,于是老师要小南再设计一个新的填数游戏用于期末考试。就是用“*”画出一个立方体,并将立方体图形的三面分别按照规律填上大写字母“A”~“Z”字母、小写字母“a”~“z”和数字“1”~“9”。填充的过程按照字母和数字的顺序从上到下从左至右进行。
立方体的边长n定为多少好呢?小南让老师给出一个句子,将句子的长度len和句子中单词的个数m的最大公约数设定为立方体的边长n。例如:当老师给出的句子为“you like these things sun stars and moon”时,句子长度len为40,单词个数m为8,最大公约数为8。因此立方体的边长n为8。
注意,当n为1时,对应的立方体图形为一个星号*。同时,老师要求小南将句子中的单词颠倒顺序输出,即输出“moon and stars sun things these like you”,你能帮小南编程实现吗?
输入
多个样例。 每个样例包含一个由字母组成的句子,句子的首尾没有多余的空格,长度不超过200,句子中的单词之间用一个空格分开。
输出
每个样例首先输出一个颠倒单词顺序的句子,然后按照填充要求输出一个正确的立方体图形。样例输出结果之间用一个空行分开。
样例输入 Copy
I do you like these things sun stars and moon you love csu
样例输出 Copy
do I ** *** ** moon and stars sun things these like you ******** *ABCDEF** *GHIJKL*1* *MNOPQR*23* *STUVWX*456* *YZABCD*7891* *EFGHIJ*23456* ********789123* *abcdef*45678* *ghijkl*9123* *mnopqr*456* *stuvwx*78* *yzabcd*9* *efghij** ******** csu love you *** *A** ***1* *a** ***
#include<stdio.h>
#include<string.h>
#define R 201
int Divisor(int x, int y); //寻找最大公约数的函数
void Paint(int x); //画立方体的函数
int main()
{
char a[R];
int i, j, l, len, c, n, d;
while(~scanf("%[^\n]" , a)){ // *该处解释在代码后面
while(getchar() != '\n');
len = strlen(a);
for(i = 0,l = 0;i < len;i ++){
if(a[i] == ' ')
l ++;
}
l += 1;
if(len == 1)
printf("%c\n" , a[0]); //输入字符串只有一个则直接打印
else{
for(i = len - 1,d = 0,c = 1;i >= 0;i --,d ++){ //将字符串反向输出
if(a[i] == ' ' && c == 1){
for(j = i+1;j < i+1+d;j ++)
printf("%c" , a[j]);
printf(" ");
c = 0;
d = 0;
}
if(a[i] == ' '){
for(j = i+1;j < i+1+d;j ++)
printf("%c" , a[j]);
d = 0;
}
if(i == 0){
for(j = 0;j < d;j ++)
printf("%c" , a[j]);
d = 0;
}
}
printf("\n");
}
n = Divisor(len, l);
if(n == 1)
printf("*\n\n");
else
Paint(n);
}
return 0;
}
int Divisor(int x, int y){ //寻找最大公约数使用辗转相除法(欧几里得算法)
int a, b, t;
a = x;
b = y;
while(b){
t = b;
b = a % b;
a = t;
}
return a;
}
void Paint(int x){
int up, f, i, g, k, j, down;
char Ch, ch, h;
up = x - 1; f = x; g = x - 2;
while(up){
printf(" ");
up --;
}
while(f){
printf("*");
f --;
}
printf("\n");
Ch = 'A'; ch = 'a'; h = '1'; k = 0;
while(g){
for(i = 0;i < g;i ++)
printf(" ");
printf("*");
for(i = 0;i < x - 2;i ++){
if(Ch > 'Z')
Ch -= 26;
printf("%c" , Ch ++);
}
printf("*");
for(i = 0;i < k;i ++){
if(h > '9')
h -= 9;
printf("%c" , h ++);
}
printf("*\n");
g --;
k ++;
}
f = x;
while(f){
printf("*");
f --;
}
for(i = 0;i < x - 2;i ++){
if(h > '9')
h -= 9;
printf("%c" , h ++);
}
printf("*\n");
down = x - 2; j = x - 2; ch = 'a';
while(j){
printf("*");
for(i = 0;i < x - 2;i ++){
if(ch > 'z')
ch -= 26;
printf("%c" , ch ++);
}
printf("*");
for(i = 0;i < j - 1;i ++){
if(h > '9')
h -= 9;
printf("%c" , h ++);
}
printf("*\n");
j --;
}
down = x;
while(down){
printf("*");
down --;
}
printf("\n\n");
}
" * "处说明:孩子们,这题“ * ”处如何处理读入多样例字符串是一个难点。普通的scanf("%s" , a);在遇到空格就会停止,显然没法读入一行句子。而fgets(a, N, stdin);函数则会一直读入直到换行符\n为止或数组元素达到N个为止,由于这一题样例输入就直接是句子,所以没法对fgets函数中的N进行调整,自然会出现读入过多或者过少的问题。
因此这题我找到两个解决的办法,其中都需要使用scanf("%[^\n] , a);来读入字符串。[] 表示一个字符集合,^ 表示取反,\n
表示换行符,所以 %[^\n]
整体的意思是读取输入的字符,直到遇到换行符 \n
为止。但是需要注意:这种读取方式不会读取换行符。因此在输入完数据后,换行符仍然留在输入缓冲区中,这可能会影响后续的输入操作。例如,如果后续使用 scanf
或 getchar
读取下一个字符,可能会读取到这个遗留的换行符,而不是期望的数据。
为了处理掉烦人的换行符,孩子们,我来告诉你们两种办法。
第一种是使用while(getchar() != '\n');,其主要作用是清空输入缓冲区。程序会不断地从输入缓冲区中读取字符,直到读取到换行符 '\n'
为止,而循环体执行语句为空,不会对已读入的数据产生任何影响,从而清空缓冲区中当前行的剩余字符。当然,你不妨试试不要这一行语句,那样在OJ上答案肯定是错误的,因为除第一行字符串之外其他所有读入的字符串都乱套了。
第二种则是将读入函数稍加修改为scanf("%[^\n]%*c", a);。%*c
是一个特殊的格式说明符:%c
表示读取一个字符,*
表示该输入项被抑制,即读取该字符但不存储它,也就是丢弃该字符。
以上两种方法都是能处理掉烦人的字符串的方法,这些应该会对你们有所帮助。
孩子们,这题确实比较难。不仅仅是需要完成的任务比较多,而且每一项小任务都需要注意处理细节或者运用一定的数学知识,就像计算最大公约数的函数就使用了欧几里得法,还有打印图形时将复杂的立方体简单化,将视觉上三维的立体图形转化为二维的平行四边形,这样就更方便找到其图形的规律。孩子们,题目虽难,但是只要我们耐心做好每一个小模块,就一定可以成功。Man!
标签:10,OJ,中南大学,++,int,while,printf,立方体,句子 From: https://blog.csdn.net/2401_87217723/article/details/144773818