题意:
给定正整数N,找到满足m*n = N的可能中使得m>=n且m-n最小。在m*n的矩阵中按照数组从大到小以顺时针方向依次填写。
思路分析:
- 数组排序
- 将矩阵从外圈到内圈依次赋值,每一圈按照 上右下左的顺序填充,并且最后一个不填。每一圈给定两个坐标,左上角和右下角。(i,j), (a[0],a[1]);每填充一圈
i++,j++, a[0]–,a[1]–.即向内缩一圈。当i <= a[0] && j <= a[1]填充结束。最后一圈如果左上角和右下角行值相等,i = a[0]则为横线只有列值增加填充,如果左上角和右下角列值相等,j = a[1]则为竖线只有行值增加填充。
坑点
数组不能开在main函数中,否则会发生栈溢出,3,5测试点不过。需要设置为全局变量,或者使用vector.因为vector内存空间是动态分配的,所以在堆上,空间大些。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
bool cmp(int a, int b) {
return a > b;
}
void getRC(int n, int a[]);
const int maxn = 10010;
int c[maxn];
int mp[maxn][maxn];
int main(int argc, char** argv) {
int n, i = 0, j = 0;
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%d", &c[i]);
sort(c, c + n, cmp);
int a[2], k = 0, t;
getRC(n, a);
int r = a[0], co = a[1];
i = 0;
// t = ((a[1] & 1) == 0 ? a[1] / 2 : a[1] / 2 + 1); // == 的优先级大于 &
// 从外到里一圈一圈赋值,不要每一边得尾。
for (int m = 0; i < a[0] && j < a[1]; m++) {
if (j == a[1] - 1 ) { // 最后一次若左上角和右下角列值相等。
for (; i < a[0]; i++)
mp[i][j] = c[k++];
} else if(i == a[0] - 1) { // 左上角右下角行相等
for (; j < a[1]; j++)
mp[i][j] = c[k++];
} else {
for (; j < a[1] - 1; j++)
mp[i][j] = c[k++];
for (; i < a[0] - 1; i++)
mp[i][j] = c[k++];
for (; j > m; j--)
mp[i][j] = c[k++];
for (; i > m; i--)
mp[i][j] = c[k++];
}
i++;
j++;
a[0]--;
a[1]--;
}
for (int i = 0; i < r; i++) {
for (int j = 0; j < co; j++) {
if (j == co - 1)
printf("%d\n", mp[i][j]);
else
printf("%d ", mp[i][j]);
}
}
return 0;
}
void getRC(int n, int a[]) {
int sub = n;
a[0] = -1;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
if ((n / i - i) < sub) { // 可以不加判断直接赋值,因为遍历过程左右边界是往里扩的,差值只会越来越小。
a[0] = n / i;
a[1] = i;
sub = a[0] - a[1];
}
}
}
if (a[0] == -1) {
a[0] = n;
a[1] = 1;
}
}