题目 1188: 做幻方

2023-11-20 12:59
文章标签 题目 幻方 1188

本文主要是介绍题目 1188: 做幻方,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

Apple最近迷上了做幻方,Apple还是个中高手,只要你说个奇数N就能把N*N的幻方做出来。其实你可以比他做得更好的。Apple总是画得很乱,而你可以利用程序排得很整齐^_^ 幻方的要求:每一行,每一列,还有两条斜线上数字的和都相等.

输入

每行一个奇数N(0< N < 30),输入0结束

输出

输入一个奇数,输出一个幻方,顺序参照样板输出;同一列的数右对齐,数与数用一个空格分开;输出完以后加一个回车。

样例输入
5
1
0
样例输出
11 18 25  2  9
10 12 19 21  34  6 13 20 22
23  5  7 14 16
17 24  1  8 151

        其实这个题目降低了难度,Google一下你就知道,除了奇数次的幻方,还有偶数次的幻方,而且偶数次比奇数次难度要高出不少,而本题目仅要求输出奇数次,🙏感谢感谢。另外我采用的就是最原始的办法,一种一种情况去判断、去解决,网上大佬的代码秀得我头皮发麻(我啥时候能写出那种优美的代码😭😭),

代码就显得略长了一些,但是能保证大部分人一遍就看懂,如果不懂,Q1782356223!好了废话少说,开工!
        

        我使用的是“楼梯法”,我结合着下面这张图说明一下!

        1513330996155046.jpg

        首先,我们先声明一个二维数组matrix[n][n](n是幻方的行数);
        然后,把数字“1”放在第一行的中间位置,这个中间位置如何确定呢?答案就是n/2(n是幻方的行数),也就是matrix[0][n/2]

        然后,我们就依次将2、3、4、5、、、n 填入数组中,具体怎么个填充法?每个数字放在二维数组的哪个位置?这都要通过“楼梯法”解决问题。

        

        “楼梯法”的规则就是就是上图中箭头指的方向,在将其翻译成人话之前,请大家把上图中的二维数组的每一行、每一列都想像成一个个首尾相连的圆圈,也就是第一行是一个首尾相连的圆圈,这样以来,每一行、每一列的最后一个元素的下一个位置又重新回到了该行/该列的第一个元素位置,例如15的下一个位置是17、16的下一个位置是23,22的下一个位置是4;把列想像成一个圆圈,就会出现9的下一个位置是15、2的下一个位置是8、25的下一个位置1……

    

        然后把“楼梯法”翻译成人话就是:   “每次将一个数字填入上一个数字的右上方(比如上图中数字8填到了数字7的右上方,也就是 matrix[i-1][j+1] 的位置),如果上一个数字的右上方已经超出了二维数组的界限,例如,数字9应该填到数字8的右上方,但是8的右上方明显超出二维数组的界限, 这时就将其放到右上方所在行/列的第一个位置(8的右上方也就是15的上方就是第5列这个圆环上、15这个元素的下一个位置,由于圆圈首尾相连,15的下一个位置自然就是9所在的位置),同理17应该放到16的右上方,但是超出边界,则把17放到第一行的第一个位置。

        如果右上方没有超出边界,但是已经有元素存入其中(例如6应该放到5的右上方,但是该位置已经被1事先给占了),这时就将元素放到上一个元素的下一个位置例如,5的右上方被占了,那就把6放到5的下方;21应该放到20的右上方,也就是16所在的位置,但是明显该位置已经被16给占了,所以把21放到20的下面。

        好了,以上就是“楼梯法”的规则了,简单来说就是一句话:新元素往上一个元素的右上角存,超出边界,则放到右上角所在的行/列的下一个位置,如果新元素位置已被占据,则存在上一个元素的下一个位置。

        
注意事项: 当新元素的位置超出边界时,我们要判断是行超出边界还是列超出边界,不同的原因对应着不同的解决方法,详见下方代码。

              另外,我确实没搞懂题目中的“右对齐”是怎么回事,所以就采用了最原始的方法进行打印输出,所以显得代码略长,但是能保证你看一遍就懂

参考代码:

#include <stdio.h>
#include <math.h>void create(int n) {if (n == 1) {//如果n等于1,直接输出printf("1\n\n");} else {//定义并初始化一下二维数组int matrix[n][n];for (int i = 0; i < n; ++i) {for (int j = 0; j < n; ++j) {matrix[i][j] = 0;}}//开始构造幻方int i = 0, j = n / 2;//i、j作为每次填入元素的下标,i、j的值一直都在变,每一次都要判断是否已经超出二维数组的界限int k = 0, m = 0;//专门针对i和j都出现问题时所用matrix[0][n / 2] = 1;//先把1的位置摆在第一行正中央int key = 2;//key作为填入矩阵的数据,每次递增int count = 1;//计数器,当count等于n*n时表示二维数组已经填满,结束循环//一直循环到矩阵每一个位置都填充上数据,正好需要填充n*n次则结束循环while (1) {if (count == pow(n, 2)) {break;} else {//计数器还没到n*n次,说明还有空白位置,可以接着填入元素//按照"楼梯法"计算下一个数据元素的存储位置k = i;i -= 1;m = j;j += 1;//分别判断i、j是否超出了二维数组的表示范围if (i < 0 && j <= n - 1) {//i的问题,单独处理i:j保持不变,i=n+i;i = n + i;//i=-1时,n+i又跑到最后一行了//下标问题解决了,现在需要看该位置是否已经有元素填进去了if (matrix[i][j] == 0) {//等于0意味着该位置为空,可以填入matrix[i][j] = key;} else if (matrix[i][j] != 0) {//该位置已经不为空,不可填//将i、j恢复原状i = k;j = m;//恢复原状后,将新元素填写到非法位置的下一个i += 1;//j保持不变,i加1matrix[i][j] = key;}} else if (i >= 0 && j > n - 1) {//j的问题,单独处理j:i不变,j=n-j;j = n - j;//下标问题解决了,现在需要看该位置是否已经有元素填进去了if (matrix[i][j] == 0) {//等于0意味着该位置为空,可以填入matrix[i][j] = key;} else if (matrix[i][j] != 0) {//该位置已经不为空,不可填//将i、j恢复原状i = k;j = m;//恢复原状后,将新元素填写到非法位置的下一个i += 1;//j保持不变,i加1matrix[i][j] = key;}} else if (i < 0 && j > n - 1) {//i、j都出问题了,i、j都要做相应的处理i = n + i;j = n - j;//下标问题解决了,现在需要看该位置是否已经有元素填进去了if (matrix[i][j] == 0) {//等于0意味着该位置为空,可以填入matrix[i][j] = key;} else if (matrix[i][j] != 0) {//该位置已经不为空,不可填//将i、j恢复原状i = k;j = m;//恢复原状后,将新元素填写到非法位置的下一个i += 1;//j保持不变,i加1matrix[i][j] = key;}} else {//i、j都没出问题,一切正常,万事大吉,正常操作,将新的key存入新的matrix[i][j]//下标问题解决了,现在需要看该位置是否已经有元素填进去了if (matrix[i][j] == 0) {//等于0意味着该位置为空,可以填入matrix[i][j] = key;} else if (matrix[i][j] != 0) {//该位置已经不为空,不可填//将i、j恢复原状i = k;j = m;//恢复原状后,将新元素填写到非法位置的下一个i += 1;//j保持不变,i加1matrix[i][j] = key;}}//填完一个数字后,将key值加1,为下一次的填充作准备key++;//count也要加1,表示又有一个数字填充进数组count++;}}//题目要求倒着输出,即先输出最后一行,再输出倒数第二行...屁事真多,还得右对齐,我艹if (pow(n, 2) < 10) {for (int l = n - 1; l >= 0; --l) {for (int i1 = 0; i1 < n; ++i1) {printf("%d ", matrix[l][i1]);}//输完一行,另起一行printf("\n");}} else if (pow(n, 2)>= 10 && pow(n, 2) <= 99) {for (int l = n - 1; l >= 0; --l) {for (int i1 = 0; i1 < n; ++i1) {if (matrix[l][i1] < 10) {printf(" %d", matrix[l][i1]);} else if (matrix[l][i1] >= 10 && matrix[l][i1] <= 99) {printf("%d", matrix[l][i1]);}printf(" ");}//输完一行,另起一行printf("\n");}} else if (pow(n, 2) >= 100) {for (int l = n - 1; l >= 0; --l) {for (int i1 = 0; i1 < n; ++i1) {if (matrix[l][i1] < 10) {printf("  %d", matrix[l][i1]);} else if (matrix[l][i1] >= 10 && matrix[l][i1] <= 99) {printf(" %d", matrix[l][i1]);} else if (matrix[l][i1] >= 100) {printf("%d", matrix[l][i1]);}printf(" ");}//输完一行,另起一行printf("\n");}}//输完一组,输出一个空行用于输出下一个幻方printf("\n");}}int main() {int n = 0;while (~scanf("%d", &n) && n) {create(n);}return 0;
}

 

这篇关于题目 1188: 做幻方的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/394786

相关文章

【计算机组成原理】部分题目汇总

计算机组成原理 部分题目汇总 一. 简答题 RISC和CICS 简要说明,比较异同 RISC(精简指令集)注重简单快速的指令执行,使用少量通用寄存器,固定长度指令,优化硬件性能,依赖软件(如编译器)来提升效率。 CISC(复杂指令集)包含多样复杂的指令,能一条指令完成多步操作,采用变长指令,减少指令数但可能增加执行时间,倾向于硬件直接支持复杂功能减轻软件负担。 两者均追求高性能,但RISC

上海邀请赛 A题目 HDU 5236(dp)

先求出没有ctrl+s的时候构造长度为i的期望f[i] 。然后枚举保存的次数,求出最小即可。 #include<cstdio>#include<cstdio>#include<cmath>#include<queue>#include<stack>#include<string>#include<cstring>#include<iostream>#include<map>

华为od-C卷200分题目3 - 两个字符串间的最短路径问题

华为od-C卷200分题目3 - 两个字符串间的最短路径问题 题目描述 给定两个字符串,分别为字符串A与字符串B。 例如A字符串为ABCABBA,B字符串为CBABAC可以得到下图m*n的二维数组,定义原点为(0, 0),终点为(m, n),水平与垂直的每一条边距离为1,映射成坐标系如下图。 从原点(0, 0)到(0, A)为水平边,距离为1,从(0, A)到(A, C)为垂直边,距离为1

CTF-蓝帽杯 2022 初赛Misc计算机取证题目详解

使用工具:Volatility、Passware Kit、Arsenal Image Mounter、DiskGenius 题目文件如下: 首先要知道这些文件是什么: dmp后缀指Dump文件,是windows系统中的错误转储文件。包含计算机程序运行时的内存信息的文件。通常操作系统或应用程序在遇到系统崩溃、死机或其他严重错误时,会自动将程序运行环境的所有信息导出到一个.dmp文件中。所以

「LeetCode」递归题目之第N个Tribonacci数

Tribonacci序列Tn定义: T0=0, T1=1, T2=1, n>=0时,Tn 3 = Tn Tn 1 Tn 2 限制条件是: 0<=n<=37, 32位整型。 我直接用C 撸了下面的代码, #include <iostream>using namespace std;class Solution {public:int tribonacci(int n) {if (n ==

算法训练与程序竞赛题目集合(L4)

目录 L4-103 就不告诉你 输入格式: 输出格式: 输入样例: 输出样例: L4-104 Wifi密码 输入格式: 输出格式: 输入样例: 输出样例: L4-105 冠军魔术 输入格式: 输出格式: 输入样例 1: 输出样例 1: 输入样例 2: 输出样例 2: L4-106 判断题 输入格式: 输出格式: 输入样例: 输出样例: L4-107

【java编程(在线笔试)】【链表】两道k个一组翻转链表题目(包含非递归和递归两种解法)

一、给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点也翻转顺序。 1. 非递归解法 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) {

链表题目之模拟类

还有一些题目是没有特别复杂的技巧,但是考察仔细程度以及基本的链表处理能力,从而考察在基本的逻辑处理上考虑的全面和细致层度。这类题目对于业务代码编码能力的鉴定的确是有一些帮助。 分隔链表(86) 题目:86. 分隔链表 把大于等于的放到一个新的链表上,当然第一个可能也被操作,直接用虚拟头节点,最后链表拼接,记得确保新链表的尾部是nil 新链表采用尾插法实现保障顺序 旧链表记得手摸模拟去掉一个节点

Java编程小练习题目

题目: 你和相亲对象正在餐厅里约会。键盘录入两个整数,用来分别表示你和对象的衣服的时髦度。(手动录入0-10之间的整数,不能录入其他的)。如果你的时髦度大于你对象的时髦度,相亲就成功,打印输出true,反之则输出false。 答案: import java.util.Scanner;public class yuehui {public static void main(String[] ar

若干题目2

五一过后,便返回学校了。返回学校之后,便是疯狂的刷题,复习以前的知识。数据结构、操作系统、计算机网络、linux、C++等。唉,复习的想吐了,都有想撕书的冲动了。终于,这艰难的几天过去了,周六来了。好激动啊。因为10点面试,早上8点起床,整理了一番后,蓄势待发。找了一间比较安静的教室,大概也就9点10分了。看了几眼书,其实根本就看不进去。开始把耳机拿出来,等着电话过来,啊啊啊,但是悲剧了,耳机是耳