乙级1050
第一次看到时间限制200ms以为是找规律,找了半天没找到,后来才觉得这应该是模拟题,模拟题意将数字“螺旋式”填充进去
1.m x n的确定
遍历找最大公约数
如果是i~N遍历的话 循环到最后出来的值必然是m,然后N/m出来的就是n,并且m必然>n,举个栗子 就像11质数,遍历到最后i=N,那么这时候m=i,必然最大
还有个剪枝的好方法,这题不会在这上面刁难人的,所以怎么做都行:
循环for(int i = 1; i*i<=N;i++)
这里用i*i<=N就是寻找前半边即可,这样剩下部分在i之后的值必然大于i,也就是先确定n,再计算出m
2.螺旋模拟
螺旋分四个方向,右、下、左、上
所以可以对四个反向直接模拟,一圈结束之后,在新的起点再来一圈,直到数字用完
每一圈要确定好方向,并且到一个位置要留意是不是到了边界,如果到了边界就表示要换方向了
所以将矩阵四个角的点的坐标记录下来为p1,p2,p3,p4,这四个点就是是否到边界的标准,比如向右,就要留意x轴上的值不能超过p2的x值,如果相等,那就表示下一步就要换方向了,而且肯定是向下,以此类推。
值得注意的是,最后向上边界并不是在p1点上,而是即将到p1点的时候就要停止换方向,设动点为p,那么就是p.y+1 == p1.y;
此时就要开始新的一圈
对于新的一圈,之前设的端点要全往里缩一圈,就是第二圈矩阵了
AC代码:
#include<bits/stdc++.h>
using namespace std;
struct coordinate{
int x;
int y;
};
coordinate p1,p2,p3,p4,p;
bool comp(int a,int b){
if(a>b) return true;
return false;
}
int main(){
int N;
cin>>N;
int *a = new int[N];
int m,n; //行,列
for(int i = 1; i*i<=N;i++){
if(N%i==0){
n = i;
m = N/i;
}
}
int martix[m][n];
for(int i = 0;i<N;i++){
scanf("%d",&a[i]);
}
sort(a,a+N,comp);
p1.x = 0,p1.y = 0;
p2.x = n-1,p2.y = 0;
p3.x = n-1,p3.y = m-1;
p4.x = 0,p4.y = m-1;
p.x = 0,p.y = 0;
int left=1,down=0,right=0,up=0;
for(int i = 0;i<N;i++){
martix[p.y][p.x] = a[i];
// printf("m[%d][%d] = %d a[%d] = %d\n",p.y,p.x,martix[p.y][p.x],i,a[i]);
if(left){
if(p.x+1>p2.x){
p.y++;
left = 0;down = 1;
}else{
p.x++;
}
}
else if(down){
if(p.y+1>p3.y){
p.x--;
down = 0;right = 1;
}else{
p.y++;
}
}
else if(right){
if(p.x-1<p4.x){
p.y--;
right = 0;up = 1;
}else{
p.x--;
}
}
else if(up){
if(p.y-1==p1.y){//顶到头的时候注意这地方代码有点不一样
p.x++;
up = 0;left = 1;
p1.x++,p1.y++;
p2.x--,p2.y++;
p3.x--,p3.y--;
p4.x++,p4.y--;
}else{
p.y--;
}
}
}
for(int i = 0;i<m;i++){
int isfirst = 1;
for(int j = 0;j<n;j++){
if(isfirst){
printf("%d",martix[i][j]);
isfirst = 0;
}else printf(" %d",martix[i][j]);
}
printf("\n");
}
return 0;
}
百度了一下其它方式,基本大同小异。
因为我对算法复杂度并不是特别熟悉,所以在模拟的地方选择了复杂度O(n)的操作,好像好多人都是外层1个循环+内层4个循环,直接循环四个方向,再缩进