题目链接:
https://pintia.cn/problem-sets/994805342720868352/problems/994805363117768704
题目大意:
给出N个正数,将其以非递增填充到一个旋转矩阵Am*n中,从左上角开始,按照顺时针方向,矩阵行列m,n满足:m*n = N,m >= n, 且使得m - n达到最小。
思路分析:
根据给出的N,计算出满足要求的矩阵行列数,由于不能用变量作为二维数组的行列下标初始化,故采用vector变长数组的形式。
vector < vector<int> > ans(m, vector<int>(n)); //建一个n*m的数组。即m行,n列。
由于在构造旋转数组的时候,是由外到内,且每层旋转方向同为顺时针,故可记录当前的轮次c,即由外到内的层数,那么我们只要分析一层,然后在外层用一个for循环即可,不难知道,在第c层中,上边的坐标是由[c-1][c-1]~[c-1][n-c](为了理解方便,我们把四边形的顶点归为上一条边),右边的坐标是由[c][n-c]~[m-1][n-c],下边的坐标是由[m-1][n-c-1]~c[m-1][c-1],左边的坐标是由[m-c-1][c-1]~c[c][c-1]。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
int N, c, m, n = 1, pos = 0;
bool cmp(int a, int b){
return a >= b;
}
void calc(int N){ // 计算出满足要求的m,n.
for(int i = 1; i <= sqrt(1.0*N); i++){
if(N%i ==0) n = i;
}
m = N/n;
}
int main()
{
cin >> N;
calc(N);
vector <int > A(N);
for(int i = 0; i < N; i++){
cin >> A[i];
}
sort(A.begin(), A.end(), cmp);
vector < vector<int> > ans(m, vector<int>(n)); //建一个n*m的数组。即m行,n列。
int i, j;
for(c = 1; c <= (n+1)/2 ; c++){
for(j = c - 1; j <= n - c; j++){
ans[c-1][j] = A[pos++];
}
for(i = c; i <= m - c; i++){
ans[i][n - c] = A[pos++];
}
for(j = n - c - 1; j >= c-1; j--){
ans[m-c][j] = A[pos++];
}
for(i = m - c -1; i >= c ; i--){
ans[i][c-1] = A[pos++];
}
}
for(i = 0; i < m; i++){
for(int j = 0; j < n; j++){
cout << ans[i][j] ;
if(j != n - 1) cout << ' ';
}
cout << endl;
}
return 0;
}
在测试案列通过后,以为提交后会AC,可是,,,
想了很久试了一下案列,当N为质数的时候,比如N=7.得到了下面的输出结果,根据输出结果,判断可能是将数组A越界的元素
赋值给ans,所以分析内层循环后,我们发现在最后一个内层for中,当n=1时,程序会继续执行将第n-2行到第1行的数据覆盖(这里我们从第0行开始计数)。
改进代码,在内层最后一个for循环中,添加一个判断条件,pos < N,即可 AC。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
int N, c, m, n = 1, pos = 0;
bool cmp(int a, int b){
return a >= b;
}
void calc(int N){ // 计算出满足要求的m,n.
for(int i = 1; i <= sqrt(1.0*N); i++){
if(N%i ==0) n = i;
}
m = N/n;
}
int main()
{
cin >> N;
calc(N);
vector <int > A(N);
for(int i = 0; i < N; i++){
cin >> A[i];
}
sort(A.begin(), A.end(), cmp);
vector < vector<int> > ans(m, vector<int>(n)); //建一个n*m的数组。即m行,n列。
int i, j;
for(c = 1; c <= (n+1)/2 ; c++){
for(j = c - 1; j <= n - c; j++){
ans[c-1][j] = A[pos++];
}
for(i = c; i <= m - c; i++){
ans[i][n - c] = A[pos++];
}
for(j = n - c - 1; j >= c-1; j--){
ans[m-c][j] = A[pos++];
}
for(i = m - c -1; i >= c && pos < N ; i--){
ans[i][c-1] = A[pos++];
}
}
for(i = 0; i < m; i++){
for(int j = 0; j < n; j++){
cout << ans[i][j] ;
if(j != n - 1) cout << ' ';
}
cout << endl;
}
return 0;
}
也可这样。在最后一次循环前添加一个判断n为奇偶的条件。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
int N, c, m, n = 1, pos = 0;
bool cmp(int a, int b){
return a >= b;
}
void calc(int N){ // 计算出满足要求的m,n.
for(int i = 1; i <= sqrt(1.0*N); i++){
if(N%i ==0) n = i;
}
m = N/n;
}
int main()
{
cin >> N;
calc(N);
vector <int > A(N);
for(int i = 0; i < N; i++){
cin >> A[i];
}
sort(A.begin(), A.end(), cmp);
vector < vector<int> > ans(m, vector<int>(n)); //建一个n*m的数组。即m行,n列。
int i, j;
for(c = 1; c <= n/2 ; c++){
for(j = c - 1; j <= n - c; j++){
ans[c-1][j] = A[pos++];
}
for(i = c; i <= m - c; i++){
ans[i][n - c] = A[pos++];
}
for(j = n - c - 1; j >= c-1; j--){
ans[m-c][j] = A[pos++];
}
for(i = m - c -1; i >= c; i--){
ans[i][c-1] = A[pos++];
}
}
if(n%2){
for(i = c - 1; i <= m - c; i++){
ans[i][c-1] = A[pos++];
}
}
for(i = 0; i < m; i++){
for(int j = 0; j < n; j++){
cout << ans[i][j] ;
if(j != n - 1) cout << ' ';
}
cout << endl;
}
return 0;
}