【PAT B1050】螺旋矩阵 (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

 ===================================================

模拟题。螺旋、回形、蛇形诸如此类的填数字,都是一样的套路。

 

第一步:确定行m,列n。(要求m - n尽可能的小且 m >= n)

题目给定一个N,把它分解成m * n。判断素数的模板是不是可以拿来用了 ?

int func(int Num){
    int i = sqrt((double)Num);
    while(i >= 1){
        if(Num % i == 0) return i;    //拆成功了,直接返回这个值
        i--;
    }
    return 1;    //如果Num是素数,拆不了,返回1
}

第二步:填数。

因为填数要按从大到小填,事先排好序。开一个二维数组,行为m,列为n(是的,中括号里写变量,c++11支持)。

初始化二维数组值为-1,并预先填好0,0这个位置。(why?等会就明白)

x是行下标控制竖着走,y是列下标控制横着走。

首先,是横着向右走,x不动y动,我们先判断能不能往右走。

怎么判断?(解题关键点)

一是判断下一步越界了吗,即y + 1 < n吗?

二是判断这个格子之前有没有用过?即等于-1吗?(初始为-1,因为填的数全是正整数)。

如果没有越界且格子没被使用过,填数,继续判断下一步...

往下走,往左,往上走都是同一个逻辑,这里不再赘述。

 

每一次填数前,都要先判断能不能走,能走则走,不能就换路走。如何换路?请看代码。

===================================================

代码本地编译不过因为编译器标准不支持c++11,请提交至OJ上。

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <string.h>
using namespace std;
bool cmp(int a, int b){
	return a > b;
}
int func(int Num){
	int i = sqrt((double)Num);
	while(i >= 1){
		if(Num % i == 0) return i;
		i--;
	}
	return 1;
}
int main(){
	int Num, m, n, cnt = 0;
	cin >> Num;
	n = func(Num);
	m = Num / n;
	vector<int> v(Num);
	for(int i = 0; i < Num; i++) scanf("%d", &v[i]);
	sort(v.begin(), v.end(), cmp);
	int a[m][n];
	memset(a, -1, sizeof(a));
	a[0][0] = v[0];
	int x = 0, y = 0;//x是行下标,控制竖着走。y是列下标,控制横着走 
	while(cnt < Num-1){
		while(y+1 < n && a[x][y+1] == -1) a[x][++y] = v[++cnt];
		while(x+1 < m && a[x+1][y] == -1) a[++x][y] = v[++cnt];
		while(y-1 >= 0 && a[x][y-1] == -1) a[x][--y] = v[++cnt];
		while(x-1 >= 0 && a[x-1][y] == -1) a[--x][y] = v[++cnt];
	}
	for(int i = 0; i < m; i++){
		for(int j = 0; j < n; j++){
			printf("%d", a[i][j]);
			if(j != n-1) printf(" ");
		}
		printf("\n");
	}
	return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值