PTA basic 1050 螺旋矩阵 (25 分) c++语言实现(g++)

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

输入格式:

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

输出格式:

输出螺旋矩阵。每行 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.为了形成螺旋矩阵的样式 需要的参数有 m行 n列 一个非增序排列的数组 给定的参数有元素个数N,待排序数列 ,所以第一步要把m和n计算得出,然后将数组有序(非增序)
2.题目已经给出了m,n的选择条件, 既 m-n 值最小 m>n m*n=N;  N为正整数,使用双循环取m*n==N时的m和n值,由于m>n的条件,n循环取值时小于m即可
  当m*n==N条件成立时, 取得m-n的值 和 min(初值为N)比较,如果m-n<min 则将m和n的值保存

3.螺旋数组的形成
  螺旋数组有 四个方向 递增 的边,每个边的元素个数都是有特征的
  手动推演 3*3 3*4 5*4 个元素的螺旋矩阵 按螺旋矩阵的螺旋边顺序 把每条边的元素都写出来之后 会发现一些规律
  以5*5螺旋矩阵为例 数字表示元素在顺序数组中的位置,此时行m=5,列n=5;
   1  2  3  4  5
   16 17 18 19 6
   15 24 25 20 7
   14 23 22 21 8
13 12 11 10 9
  
  第1条边 既 最上面一行       1 2 3 4 5 5个元素
  第2条边 既 除第一行外的右侧边   6 7 8 9    4个元素
  第3条边 既 除最右侧一列的底边   10 11 12 13 4个元素
  第4条边 既 除最上最下两行的左侧边 14 15 16   3个元素
  第5条边 递推            17 18 19   3个元素
  第6条边              20 21     2个元素
  第7条边              22 23     2个元素
  第8条边               24      1个元素
  第9条边              25      1个元素

观察可以得知,除第一条边外,每2条边的元素都会减1 因为每4条边方向是一圈 既 4条边会形成一个环

可以利用这个特征形成螺旋矩阵的坐标选择

4. 变量命名和含义
  元素在数组中的坐标(row,col) 左行右列
  round     %4用于判断边的方向 0位左到右的横边 1为上到下的纵边 2位右到左的横边 3为下到上的纵边 
  
  maxColNums 初值 m 当前最大横边元素数量(列数)

  maxRowNums 初值 n 当前最大纵边元素数量(行数)
  
  count     当前横(纵)边已经放入的元素个数,当count==subSize的时候,需要换边 既 round++;

  subSize   当前边的最大容量,初值maxColNums 既第一条横边的元素个数同时也是n

5.算法逻辑和边界调整
  每条边都要经历一轮元素的放入,经过循环遍历 取值放入数组
  遍历用的坐标 (raw,col) 在这条边的最后一个元素放入后,会执行一次+1操作,指向数组外
  需要手动修正坐标位置,同时向下一条边移动
  
  满足count==subSize时,移动到下一条边,round+1
  
  同时对round进行判断,是要移动到哪条边,对应横(纵)边的元素最大容量 -1,然后赋值给subSize ,同时count清零
  如果round%2==0;则下一条边是横边 横边元素最大容量 maxColNums-1
  如果round%2==1;则下一条边是纵边 纵边元素最大容量 maxRowNums-1

  round==1由 ➡️ 向 ⬇️ 移动时, 横坐标row+1 移动到下一行 ,纵坐标col-1回调到下一列
  round==2由 ⬇️ 向 ⬅️ 移动时, 横坐标row-1 向上回调一行 ,纵坐标col-1移动到左边一列 
  round==3由 ⬅️ 向 ⬆️ 移动时, 横坐标row-1 移动到上一行 ,纵坐标col+1回调到右边一列
  round==0由 ⬆️ 向 ➡️ 移动时, 横坐标row+1 向下回调一行 ,纵坐标col+1移动到右边一列

  坐标经过处理后,会位于下一条边的第一个元素的位置

  元素放入对应位置(row,col)后,要对坐标进行移动
  
  round==0;说明是➡️的横边,col++;
  round==1;说明是⬇️的纵边,row++;
  round==2;说明是⬅️的横边,col--;
  round==3;说明是⬆️的纵边,row--;

  循环直到有序数组元素全部插入螺旋矩阵中

 

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    int N,temp,i,j,m{1},n{1},min,row{0},col{0},maxRowNums{0},maxColNums{0},subSzie{0},count{0},round{0};
    cin >>N;
    vector<int> list;
    for(i=0;i<N;i++){
        cin >> temp;
        list.push_back(temp);
    }
    sort(list.rbegin(),list.rend());//非增序排列
    min=N;
    for(i=1;i<=N;i++){//求出m n
        for(j=1;j<=i;j++){
            if((i*j)==N){
                if((i-j)<min){
                    m=i;
                    n=j;
                    min=i-j;
                }
            }
        }
    }
    vector<vector<int>> rotateMetric(m,vector<int>(n));//m*n的矩阵,元素初值为0
    maxColNums=n;
    maxRowNums=m;
    subSzie=maxColNums;//第一条横边的元素个数,是n;
    for(i=0;i<N;i++){
        if(count==subSzie){//当前边元素已满,移动到下一条边
            round++;
            if(round%2==0){//更新横(纵)边可容纳的最大个数
                subSzie=--maxColNums;
            }else{
                subSzie=--maxRowNums;
            }
            count=0;//清空元素计数count
            round=round%4;//计算下条边的方向
            switch (round) {//坐标(row,col)移动到下条边的第一个元素的位置
                case 0://由↑移动到→
                    row++;
                    col++;
                    break;
                case 1://由→移动到↓
                    row++;
                    col--;
                    break;
                case 2://由↓移动到←
                    row--;
                    col--;
                    break;
                case 3://由←移动到↑
                    row--;
                    col++;
                    break;
                default:
                    break;
            }
        }
        switch (round) {
            case 0://→的边,横坐标col右移
                rotateMetric[row][col++]=list[i];
                break;
            case 1://↓的边,纵坐标row下移
                rotateMetric[row++][col]=list[i];
                break;
            case 2://←的边,横坐标col左移
                rotateMetric[row][col--]=list[i];
                break;
            case 3://↑的边,纵坐标row上移
                rotateMetric[row--][col]=list[i];
                break;
            default:
                break;
        }
        count++;//每放入一个元素+1
    }
    for(int i=0,j=0;i<m;i++){
        for(j=0;j<n-1;j++){
            printf("%d ",rotateMetric[i][j]);
        }
        printf("%d\n",rotateMetric[i][j]);
    }
    return 0;
}

 

 









posted @ 2021-05-08 16:55  keiiha  阅读(202)  评论(0编辑  收藏  举报