PAT 练习题 1050 螺旋矩阵 (25 分)

1050 螺旋矩阵 (25 分)
本题要求将给定的 N 个正整数按非递增的顺序,填入“螺旋矩阵”。所谓“螺旋矩阵”,是指从左上角第 1 个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为 m 行 n 列,满足条件:m×n 等于 N;m≥n;且 m−n 取所有可能值中的最小值。

输入格式:
输入在第 1 行中给出一个正整数 N,第 2 行给出 N 个待填充的正整数。所有数字不超过 10
​4
​​ ,相邻数字以空格分隔。

输出格式:
输出螺旋矩阵。每行 n 个数字,共 m 行。相邻数字以 1 个空格分隔,行末不得有多余空格。

输入样例:

12
37 76 20 98 76 42 53 95 60 81 58 93

输出样例:

98 95 93
42 37 81
53 20 76
58 60 76

解题思路:
1.划分行和列问题,从n的平方根向下找第一个能被n整除的数就是列数,行数=n/列数
2.将输入的数据排序(我是按照升序排列,取数据的时候从数组最后一个元素开始取)
3.最关键的部分,将数组的元素加入到螺旋矩阵中
如图:将矩阵按层划分,每一层分成四个小块(左->右,上->下,右->左,下->上 四个方向分别进行处理)
这样划的缺点,当行和列相等且都是奇数时,处理到最内层的时候就一个元素,这个时候要单独处理这个情况

解决办法如下图:将右边(上->下)小块长度增加1,下边(右->左)小块长度减少1(因为行数>=列数,所以选择纵向多处理一个数据),这样只需要一个大循环里面嵌四个小循环搞定,不需要单独处理特殊情况

#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;

int main()
{
	int n, i, j;
	cin >> n;
	vector<int> arr(n);
	for (i = 0; i<n; ++i)
		cin >> arr[i];
	sort(arr.begin(), arr.end());
	int sq = sqrt(n);
	int row, col;
	
	while (n%sq)
		--sq;
	col = sq;
	row = n / sq;
	if (n == 0)
		return 0;
	int **matrix = new int*[row];
	int count = arr.size() - 1;
	for (i = 0; i<row; ++i)
	{
		matrix[i] = new int[col];
	}
	//将数组元素加入到螺旋矩阵中
	int l;//层数
	for (l = 0; l < col / 2 + 1; ++l)
	{
		//每一层开始下标 行=列=层号
		for (i = j = l; j < col - l - 1 && count >= 0; ++j, --count)
			matrix[i][j] = arr[count];

		for (i = l; i <= row - l - 1 && count >= 0; ++i, --count)
			matrix[i][j] = arr[count];
		//从上往下的方向上比其他方向上多处理一个数据
		//循环结束指向最后一行后面,会越界,所以要减一
		--i;
		for (j = col - l - 2; j >l&&count >= 0; --j, --count)
			matrix[i][j] = arr[count];

		for (i = row - l - 1; i >l && count >= 0; --i, --count)
			matrix[i][j] = arr[count];
	}
	for (i = 0; i<row; ++i)
	{
		for (j = 0; j<col; ++j)
		{
			printf("%d", matrix[i][j]);
			if (j<col - 1)
				putchar(' ');
		}
		putchar('\n');
	}

	for (i = 0; i<row; ++i)
		delete[]matrix[i];
	delete[]matrix;
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值