PAT 乙级1050. 螺旋矩阵(25)&&蛇形填数&&51Nod 1283 最小的周长

  1. 螺旋矩阵(25)

时间限制
150 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue
本题要求将给定的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

这个题很有趣的,分几个步骤想好,就没问题了。
First,我们需要将输进去的数字排序。这个解决的办法是用C++的algorithm头文件中的sort函数进行排序,用bool自定义排序规则。这个问题算解决了。
Second,我们需要求出来列和行,他们的要求是行大于等于列,这个问题的解决和51 Nod1283的方法一样,先求出sqrt(N),也就是说从中间往N的方向就开始找。这个也算解决了
Third,就是蛇形填数,这个的解决是参考刘汝佳《算法竞赛入门经典》第二版中的例子,程序3-3。看得懂,理解了,自己能写出来那个程序了,就可以了,我把这个程序也放出来:

#include <iostream>  
using namespace std;  

const int MAXN = 10;  
int a[MAXN][MAXN] = {0};  


int main()  
{  
    int n, x, y, tot;  
    cin >> n;  

    tot = a[x=0][y=n-1] = 1;  
    while (tot < n*n)  
    {  
        while (x + 1 < n && !a[x + 1][y]){ a[++x][y] = ++tot; }  
        while (y - 1 >= 0 && !a[x][y - 1]){ a[x][--y] = ++tot; }  
        while (x - 1 >= 0 && !a[x - 1][y]){ a[--x][y] = ++tot; }  
        while (y + 1 < n && !a[x][y + 1]){ a[x][++y] = ++tot; }  
    }  

    for (x = 0; x < n; ++x)  
    {  
        for (y = 0; y < n; ++y)  
        {  
            printf("%3d", a[x][y]);  

        }  
        printf("\n");  
    }  


    return 0;  
}  

看了很久,有几个地方确实需要好好理解,道行尚浅。首先四个while语句里面的!这个符号用的很简练,判断是否放过数字这个事情也没有重开一个二维数组,也很简练。还有就是,while语句里面都是++x,++tot等等,这种把++放在前面,是不可以变的,不能变为x++的。我试了很久,体会了很久。i++和++i的区别很多考二级的都清楚了。i++,先使用i的值,再自加。++i是先自加再使用i的值。如果使用了x++,那就意味着,你走完这一步,就自动往下走了一步,但到底下一步能不能走,我们还不清楚,一旦不能走,我们还要往回撤一步,需要判断。所以,不可取。这也是刘汝佳在习题后面问的问题我的思考。
只要看懂了,理解了这个程序,解决了这三个小问题,整个问题就可以自然而然的解决了。
说起来,如果不是我提交了18遍才过,我是不会把这个题放出来的,之所以我提交一直错,主要是最后一个测试点。刚开始提示超时,后来又提示段错误,我以为是数组开小了,一直往上开,开到两百多,还不行,我就懵了,搜了一堆,又是说memset的清零速度慢,又是说bool cmp函数里应该是return a > b,我就试了很久,都不成,后来,参照他们的,把数组开的小了点,反而成了。就这样,以后长记性;
放代码:

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
bool cmp(int a,int b)
{
    return a>=b;
}

int main()
{
    int N, i, j;
    int n, m;
    scanf("%d",&N);

    int b[10000];
    for(i=0;i<N;i++)
    {
        scanf("%d",&b[i]);
    }
    sort(b,b+N,cmp);
    int factor=sqrt(N);
    if(factor*factor==N)
    {
        n=m=factor;
    }
    else {
        for(i=factor+1;i<=N;i++)
    {
        if(N%i==0)
        {
            m=i;
            n=N/i;
            break;
        }
    }
    }
    int a[m+5][n+5];
    memset(a,0,sizeof(a));
    int sum=0;
    a[0][0]=b[0];
    i=0;j=0;
    while(sum<N-1)
    {
        while(j+1<n&&!a[i][j+1])
        {
            a[i][++j]=b[++sum];
        }
        while(i+1<m&&!a[i+1][j])
        {
            a[++i][j]=b[++sum];
        }
        while(j-1>=0&&!a[i][j-1])
        {
            a[i][--j]=b[++sum];
        }
        while(i-1>=0&&!a[i-1][j])
        {
            a[--i][j]=b[++sum];
        }
    }
    for(i=0;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            if(j!=0)
            printf(" ");
            printf("%d",a[i][j]);
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值