原题干:
本题要求将给定的N个正整数按非递增的顺序,填入"螺旋矩阵"。所谓"螺旋矩阵",是指从左上角第1个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为m行n列,满足条件:m*n等于N;m>=n;且m-n取所有可能值中的最小值。
输入格式:
输入在第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
这道题是真的费脑细胞。。。
首先我们读入所有的数,存到数组里面并排好序。接着创建一个m*n的二维vector,然后将数据螺旋这存进去就好了。
这道题的难点在于,螺旋存储的时候必须要特别注意边界,稍不留神就会发生段错误。
这里我的二维vector里面的值全部初始化为0(其实无需特意初始化,因为创建好的vector里面本身就是0,但是我这里为了强调),然后当x或y超越了(0,0,m,n)这个矩阵范围,或者接下来的矩阵元素不是0(说明之前写入过数据,不能覆盖掉),就说明是边界了,需要转换方向了。
具体看代码吧,在这里说不清楚。。。
另外这道题如果使用的不是二维vector而是二维数组会导致内存超限。你也可以用new创建数组,这样和vector的道理是一样的。
下面是代码:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int cnt, m, n, nums[10010] = {0}; //m为行,n为列。
double tmp = 0.0;
scanf("%d", &cnt);
m = sqrt(cnt);
do{
tmp = 1.0 * cnt / m;
n = (int)tmp;
}while((tmp - n) && m++); //只要tmp不是整数,就m++并继续。直到m和n正好都是整数,相乘等于cnt
if(m>=n) swap(m, n); //如果m大于n,不符合题意,需要交换m和n
for(int i = 0; i < cnt; i++)//输入
scanf("%d", &nums[i]);
sort(nums, nums + cnt); //排序。小->大
vector<vector<int> > result(n ,vector<int>(m, 0)); //存放螺旋矩阵的容器result[n][m],并初始化整个矩阵为0
int x = 0, y = 0, x_min = 0, y_min = 0, x_max = m - 1, y_max = n - 1; //x和y为当前的位置。_min和_max为边缘
int flag = 3; //方向标志。1->向左,2->向下,3->向右,4->向上
while(cnt--){
result[y][x] = nums[cnt]; //添加到容器内
if((flag == 3 && x == x_max) || (flag == 3 && result[y][x+1])) //右上角
flag = 2; //向下
else if((flag == 2 && y == y_max) || (flag == 2 && result[y+1][x])) //右下角
flag = 1; //向左
else if((flag == 1 && x == x_min) || (flag == 1 && result[y][x-1])) //左下角
flag = 4; //向上
else if((flag == 4 && y == y_min) || (flag == 4 && result[y-1][x])) //左上角
flag = 3; //向右
if(flag == 1) x--;
if(flag == 2) y++;
if(flag == 3) x++;
if(flag == 4) y--; //这四行代码用来改变坐标(x,y)
}
for(int i = 0; i < n; i++){
for(int ii = 0 ; ii < m; ii++){
cout << result[i][ii];
if(ii != m - 1) cout << ' ';
}
cout << endl;
}
return 0;
}