2022-1-19 每日一题 HDU 2074 叠筐
题目描述:
叠筐
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 23830 Accepted Submission(s): 6282
Problem Description
需要的时候,就把一个个大小差一圈的筐叠上去,使得从上往下看时,边筐花色交错。这个工作现在要让计算机来完成,得看你的了。
Input
输入是一个个的三元组,分别是,外筐尺寸n(n为满足0< n <80的奇整数),中心花色字符,外筐花色字符,后二者都为ASCII可见字符;
Output
输出叠在一起的筐图案,中心花色与外筐花色字符从内层起交错相叠,多筐相叠时,最外筐的角总是被打磨掉。叠筐与叠筐之间应有一行间隔。
链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2074 或 https://www.nowcoder.com/practice/2d6505bf0d38479c9bff66e10fe39a5c
解题思路:
模拟类图形排版题
解法1:更优解法
(模板)
利用缓存数组保存输出字符矩阵,再在数组上进行排版
解题分析:
- 先不管4个角,补上成为一个正方形,最后剔除即可
- 从外向内构造
- 利用坐标 左上角(i, i) 右下角(j, j) 确定一圈
- 利用奇偶性决定每圈填充字符c
- 确定每圈边长length
注意点!!!:
- 输出格式——每组输出之间有一个空行
- 边界处理——除去n=1的情况,其余都需剔除4个角
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
char matrix[80][80];//矩阵模拟图形
int main() {
int n; //叠筐大小n
char a,b; //输入两个字符
bool firstCase = true; //第一组数据
while(scanf("%d %c %c", &n, &a, &b) != EOF) {
if(firstCase == true){
firstCase = false;
} else {
printf("\n");
}
for (int i = 0; i <= n/2; ++i) { //(i,i)每圈 左上坐标
int j = n - i - 1; //(j,j)每圈 右下坐标
int length = n - 2 * i; //每圈边长
char c;
if ((n / 2 -i) % 2 == 0) { //求当前圈填充字符
c = a;
}else {
c = b;
}
for (int k = 0; k < length; ++k) { //当前圈赋值
matrix[i][i + k] = c; //上边
matrix[i + k][i] = c; //左边
matrix[j][j - k] = c; //下边
matrix[j - k][j] = c; //右边
}
}
if (n != 1) { //去掉四个角
matrix[0][0] = ' ';
matrix[0][n-1] = ' ';
matrix[n-1][0] = ' ';
matrix[n-1][n-1] = ' ';
}
for (int i = 0; i < n; ++i) { //打印
for(int j = 0; j < n; ++j){
printf("%c", matrix[i][j]);
}
printf("\n"); //换行
}
}
return 0;
}
解法2:
找每行规律,按输出顺序,按行按列输出
解题分析:
初始代码:
逻辑直观,但是if-else嵌套过多
#include <stdio.h>
#include <stdlib.h>
void swap(char *a, char *b)
{
char c = *a;
*a = *b;
*b = c;
}
int main()
{
int n,i,j,r;//r即为row行号
char a,b;//中心花色、外筐花色
while(scanf("%d %c %c", &n, &a, &b) != EOF) {
//特殊情况,n=1,即直接输出中心花色即可
if(n == 1) {
printf("%c\n\n",a);
continue;
}
//根据中心字符是奇偶,给a,b赋值(默认中心:偶,外筐:奇)
if((n / 2 + 1)%2 == 1) {
swap(&a, &b);
}
//按行按列输出
for(int i = 1; i <= n; ++i) { //行
for(int j = 1; j <= n; ++j) { //列
if(i > n / 2 + 1) {
r = n - i + 1;
} else {
r = i;
}
if(r == 1) { //第一行和最后一行
if(j == 1 || j == n) {
printf(" ");
} else {
printf("%c",b);
}
} else {
if(j < r || j > n-r+1) {
if(j % 2 == 1) {
printf("%c", b);//奇数为外筐花色
} else {
printf("%c", a);//偶数为中心花色
}
} else {
if(r % 2 == 1) {
printf("%c", b);//由行号决定中间连续的花色是哪个
} else {
printf("%c", a);
}
}
}
}
printf("\n");
}
printf("\n");//每组输出间有一空行
}
return 0;
}
优化后代码:
减少if-else嵌套,更扁平化,但是代码可读性降低
#include <stdio.h>
#include <stdlib.h>
void swap(char *a, char *b)
{
char c = *a;
*a = *b;
*b = c;
}
int main()
{
int n,i,j,r;//r即为row行号
char a,b;//中心花色、外筐花色
while(scanf("%d %c %c", &n, &a, &b) != EOF) {
//特殊情况,n=1,即直接输出中心花色即可
if(n == 1) {
printf("%c\n\n", a);
continue;
}
//根据中心字符是奇偶,给a,b赋值(默认中心:偶,外筐:奇)
if((n / 2 + 1)%2 == 1) {
swap(&a, &b);
}
//按行按列输出
for(int i = 1; i <= n; ++i) { //行
for(int j = 1; j <= n; ++j) { //列
r = (i > n / 2 + 1)? (n - i + 1) : i;//行号赋值
if(r == 1 && (j == 1 || j == n)) { //第一行和最后一行头尾输出空格
printf(" ");
continue;
}
int p = (j < r || j > n - r + 1)? j : r;//确定花色 j决定从外到里的花色变换,r决定中间连续的花色
if(p % 2 == 1) {
printf("%c", b);//j奇数为外筐花色
} else {
printf("%c", a);//j偶数为中心花色
}
}
printf("\n");
}
printf("\n");//每组输出间有一空行
}
return 0;
}