分数 25
作者 CHEN, Yue
单位 浙江大学
本题要求将给定的 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,首先N一定要整除i,然后再判断差cha是否最小,我用的方法是如果cha 大于 m - n 则把 m - n赋给cha,这里我是直接比较cha 和 N/i - i 。要注意m - n >= 0;
- 我设置了两个矩阵,luo代表螺旋矩阵,label代表每个位置的性质,1是已经有数了,不能再加了,0是还空着,还可以再加。flag代表方向的,如果%4为0就是向右,为1就是向下,为2就是向左,为3就是向右。
- 接下来就是以螺旋的方式赋值到luo[][]里,由于是顺时针,向右向下向左向上的顺序。 i,j代表数组的行列。向右j++,向下i++,向左j–,向上i–。
- 同时判断能不能再向前走了,两种情况。1是不能超出矩阵行列2是前方有没有数字,如果已经有了(label为1),则flag++,该改变方向了。
错误分析
- m - n >= 0别忘了等于号。
代码实现
#include<stdio.h>
#include<stdlib.h>
int cmp(const void * a, const void * b){
int *pa = (int *)a;
int *pb = (int *)b;
int numa = *pa;
int numb = *pb;
return numb - numa;
}
int main(){
int N;
scanf("%d",&N);
int a[N];
for(int i = 0; i < N; i++){
scanf("%d",&a[i]);
}
qsort(a,N,sizeof(int),cmp);//最高位放在0号位
int cha = N;//
int m = 0;
int n = 0;
for(int i = 1;i <= N; i++){
if(N % i == 0){
if(cha > N / i - i && N / i - i >= 0){
cha = N / i - i;
m = N / i;
n = i;
}
}
}
int luo[m][n];
int label[m][n];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
label[i][j] = 0;
}
}
int flag = 0;
int i = 0;//螺旋矩阵的行列
int j = 0;
for(int index = 0; index < N; index++){
luo[i][j] = a[index];
label[i][j] = 1;
// j++;
if(flag % 4 == 0){
j++;
if(j == n - 1 || label[i][j + 1] == 1){
flag++;
}
continue;
}
if(flag % 4 == 1){
i++;
if(i == m - 1||label[i + 1][j] == 1){
flag++;
}
continue;
}
if(flag % 4 == 2){
j--;
if(j == 0 || label[i][j-1] == 1){
flag++;
}
continue;
}
if(flag % 4 == 3){
i--;//向上
if(i==0 || label[i - 1][j] == 1){
flag++;
}
continue;
}
}
for(int i = 0; i < m; i ++){
for(int j = 0; j < n; j++){
if(j > 0){
printf(" ");
}
printf("%d",luo[i][j]);
}
printf("\n");
}
return 0;
}
其他做法参考
PAT乙级1050:螺旋矩阵 (25)
【PAT (Basic Level) Practice】——【快乐模拟】1050 螺旋矩阵
分析
第一
首先对于m,n他们有不同的算法,我认为更好
求n,m 关键在于i*i>=N,如果<N,那么m肯定不是i
for(int i = 1;i<=N;i++)
{
if(i * i >= N && N % i == 0)
{
m = i;
break;
}
}
n = N / m;
第二
求螺旋矩阵,针对的是圈数,如果m是偶数层数就是m / 2 ,如果是奇数还要加1
【解释】
例如 i = 0或1。
c - 1 - i;//右数第i+1列
r - 2 - i;//倒数第i+2行
int circle = m/2 + m%2;
for (i=0;i<circle;i++)//圈数
//r和c是行列k是个数
{
for (j=i;j<(c-i) && k<N;j++)//上面的行,从左边到右边,列变行不变
b[i][j] = a[k++];
for (j=i+1;j<(r-i) && k<N;j++)//右边的列,从上面到下面,行变列不变
b[j][c-1-i] = a[k++];
for (j=c-2-i;j>=i && k<N;j--)//下面的行,从右边到左边,列变行不变
b[r-1-i][j] = a[k++];
for (j=r-2-i;j>i && k<N;j--)//左边的列,从下面到上面,行变列不变
b[j][i] = a[k++];
}
不太好理解
往右往下指标都是增加的,往左往上指标都是减少的。
j是充当变化的量,有时候在第一个位置有时候第二个位置。
例如当第一轮第一行完事,j到行那里,从i+1开始不断增加。而列指标c-1-i则是表示最右列不变。
第三个for行就不能变了,j回到列,从右数第二个开始减少,第四个for类似。
要注意第四个for的j不能等于i。
第二轮同理,j = i 从第二行开始,再从右2列开始,再从倒数第二行开始,再从左2列开始等等等等。