题目:1050 螺旋矩阵 (25 分)
本题要求将给定的 N 个正整数按非递增的顺序,填入“螺旋矩阵”。所谓“螺旋矩阵”,是指从左上角第 1 个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为 m 行 n 列,满足条件:m×n 等于 N;m≥n;且 m−n 取所有可能值中的最小值。
输入格式:
输入在第 1 行中给出一个正整数 N,第 2 行给出 N 个待填充的正整数。所有数字不超过 1,相邻数字以空格分隔。
输出格式:
输出螺旋矩阵。每行 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, 且m−n 取所有可能值中的最小值,最快的方法就是对N开根号,根号前后满足的m和n就会是 m-n 中的最小值。这个规律是可以发现的,拿几个数来设想只要满足了就用,类似于数学归纳吧。比如9, 开根号得到3,3×3 确实是两约数的最小差。10开根号取整为3, 3不是约数就在根号前后找,找到2和5满足。不放心的话可以再找几个数,实际上这样差不多了,毕竟不是真的证数学归纳法。
- 蛇形填数只要做好判断就没问题。在确定填数之前要判断有没有越界和有没有被填过了,填过的不重复填。然后注意++放变量前面和后面的区别。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cctype> 4 #include <iostream> 5 #include <sstream> 6 #include <cmath> 7 #include <algorithm> 8 #include <string> 9 #include <stack> 10 #include <queue> 11 #include <vector> 12 #include <map> 13 using namespace std; 14 15 int a[10000][1000]; 16 int num[10000]; 17 18 bool cmp(int a,int b) 19 { 20 return a > b; 21 } 22 23 int main() 24 { 25 int n, m, r; 26 int minn=9999; 27 memset(a, 0, sizeof(a)); 28 scanf("%d", &n); 29 for(int i = 0; i < n; i++) 30 scanf("%d", &num[i]); 31 sort(num, num + n, cmp); 32 for(int i = 1; i <= sqrt(n); i++) 33 { 34 if(n%i == 0 && minn > n/i-i) //如果i是n的约数 && 两约数之差最小 35 { 36 minn = n / i - i; 37 r = i; //r列 38 m = n / r; //m行 39 } 40 } 41 n = 0; 42 int x = 0, y = 0; 43 a[x][y] = num[0]; 44 while(n < m * r - 1) //可要记得是从0开始数的 45 { 46 while(y + 1 < r && ! a[x][y + 1]) 47 a[x][++y] = num[++n]; 48 while(x + 1 < m && !a[x + 1][y]) 49 a[++x][y] = num[++n]; 50 while(y - 1 >= 0 && !a[x][y - 1]) 51 a[x][--y] = num[++n]; 52 while(x - 1 >= 0 && !a[x - 1][y]) 53 a[--x][y] = num[++n]; 54 } 55 for(int i = 0; i < m; i++) 56 { 57 for(int j = 0; j < r; j++) 58 { 59 printf("%d",a[i][j]); 60 if(j != r-1) 61 printf(" "); 62 } 63 printf("\n"); 64 } 65 return 0; 66 }
总结:
比较大的数组作为全局变量好像比局部变量要能扛一点。
判断是不是约数时,竟一下没想到能否用取余判整除,用的是 n / i * i 是否等于 n,有点太死板。