草庐IT

“蛇形”方阵的构造

I am a teacher! 2023-03-28 原文

        编写一个程序,将自然数1~n2“蛇形”填入n×n矩阵中。例如,当n=5时,构造的方阵如下。

      

    (1)编程思路1。

        分析数的填法,是按“从右上到左下”的”蛇形”或“从左下到右上”的”蛇形”,沿平行于副对角线的各条对角线上,将自然数从小到大填写。

        设用(i,j)表示矩阵元素的坐标,初始时,i=0,j=0。

        先从右上到左下填数,当从右上到左下时,坐标i增加(i++),坐标j减小(j--),当j减到小于0(副对角线及以上部分从右上到左下填写时),或i加到大于n-1(副对角线以下部分从右上到左下填写时)时结束。然后调整坐标(i,j),调整方法为:当在副对角线及以上时(此时j<0且i<n),j=0;当过副对角线后(此时i>n-1),i=n-1,j=j+2。调整坐标后,再开始从左下向右上填数。

        当从左下到右上时,坐标i减小(i--),坐标j增加(j++),当i减到小于0(副对角线及以上部分从左下到右上填写时),或j加到大于n-1(副对角线以下部分从左下到右上填写时)时结束。然后调整坐标(i,j),调整方法为:当在副对角线及以上时(此时i<0且j<n),i=0;当过副对角线后(此时j>n-1),i=i+2,j=n-1。调整坐标后,又开始从右上向左下填数。

        如此循环,直到n*n个数填完为止。

        (2)源程序1。

#include <stdio.h>
#define  N  19
int main()
{
    int a[N][N];
    int n,i=0,j=0,k=1;            // i,j是矩阵元素的下标,k是要填入的自然数
    scanf("%d",&n);
    while(i<n && j<n)
    {
        while(i<n && j>-1)       // 从右上向左下填数
        { a[i][j]=k++; i++ ;j--; }
        if ((j<0)&&(i<n)) j=0;  // 副对角线及以上部分的新i,j坐标
        else {j=j+2; i=n-1;}    // 副对角线以下的新的i,j坐标.
        while(i>-1 && j<n)      // 从左下向右上
        { a[i][j]=k++; i--; j++; }
        if(i<0 && j<n) i=0;
        else{i=i+2; j=n-1;}
    }
    for (i=0;i<n;i++)
    {
        for (j=0;j<n;j++)
            printf("%4d",a[i][j]);
        printf("\n");
    }
    return 0;
}

        (3)编程思路2。 

        n×n矩阵有2*n-1条平行于副对角线的对角线(下面简称为斜线)。例如,n=5时,有9条斜线。可将这9条斜线按从上到下用编号k依次标记为1~9。K=5时为副对角线,k<5时,斜线位于副对角线上面。

        由题目给出的5×5方阵结果知,该方阵有9条斜线。第1条斜线上填写1个数,第2条斜线上填写2个数,…,第5条斜线上填写5个数,第6条斜线上填写4个数,…,第9条斜线上填写1个数。

        设第k条斜线上需要填写的数字个数为q。显然有

        当k<=n时,q=k;  当k>n时,q=2*n-k。

        设用(i,j)表示矩阵元素的坐标,1≤i≤n,1≤j≤n。

        第k条斜线上的坐标(i,j)一定满足等式: i+j=k+1

        例如,第3条斜线上的3个元素的坐标从右上到左下依次为 (1,3)、(2,2)、(3,1),满足i+j=k+1=4。同时,可以看出,第3条斜线上的元素坐标i从1到3。

        再如,第4条斜线上的4个元素的坐标从左下到右上依次为 (4,1)、(3,2)、(2,3)、(1,4),满足i+j=k+1=5。同时,可以看出,第4条斜线上的元素坐标j从1到4。

        由此,可找出第k条斜线上填写的q个元素中的第p个元素的坐标(i,j)与k、p、q的关系。

        当k为奇数时,斜线上的数字从右上到左下填写,i=p,j=q+1-p;

        当k为偶数时,斜线上的数字从左下到右上填写,i=q+1-j,j=p。

        但当k>n时,此时斜线在副对角线的下方,需要对坐标再修正一下。

        例如,第6条斜线上的4个元素的坐标从左下到右上依次为 (5,2)、(4,3)、(3,4)、(2,5),同样满足i+j=k+1=7。但是,第6条斜线上的元素坐标j从2到5,i从5递减到2。而按上面的关系计算出的第6条斜线上的元素坐标j从1到4,i从4递减到1。此时,只需要将计算出的坐标i和j的值均加上1(也即n-q)即可。

        同样,考察第7条斜线上的3个元素的坐标从右上到左下依次为 (3,5)、(4,4)、(5,3),同样满足i+j=k+1=8。但是,第7条斜线上的元素坐标i从3到5,j从5递减到3。而按上面的关系计算出的第7条斜线上的元素坐标i从1到3,j从3递减到1。此时,只需要将计算出的坐标i和j的值均加上2(也即n-q)即可。

        计算出了每条斜线上应该填写的每个元素的坐标,在该坐标位置填上相应的数字。采用循环将这2*n-1条斜线上均填写上数字,则“蛇形”方阵就可以构造完成。

        (4)源程序2。

#include <stdio.h>
#define  N  20
int main()
{
    int a[N][N];
    int n,i,j,k=1,m,p,q;
    scanf("%d",&n);
    m=1;                  // m是要填入的自然数
    for (k=1;k<2*n; k++)  // 第k条平行与副对角线的对角线
    {
       if (k<n) q=k;      // q是第k条对角线上填写数字的个数
       else  q=2*n-k;
       for (p=1;p<=q;p++)
       {
           if (k%2) { i=p; j=q+1-p;}
           else  { i=q+1-p; j=p; }
           if (k>n) { i=i+n-q;  j=j+n-q; }
           a[i][j]=m++;
       }
    }
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=n;j++)
            printf("%4d",a[i][j]);
        printf("\n");
    }
    return 0;
}

         (5)编程思路3。 

        观察图1所示的蛇形阵可知,方阵在逐个填数构造的过程中,是沿两种斜线进行的,一种是右上到左下(斜向下),一种是“左下到右上”(斜向上)。     

      

                                                        图1 蛇形方阵的构造示意图

        设当前已填入数字的位置坐标为(i,j),i和j均在0~n-1之间。若按斜向下填写,则下一位置为row++、col-- ;若按斜向上填写,则下一位置为row--、col++。由于下一位置可能超出方阵的边界,因此有时需要调整。调整有4种情况,下面分别进行说明。

        斜向上填写时,会出现两种情况:

        (1)超过了首行的位置(即i==-1),如图1(a)所示,3填写好后,下一个数4的计算位置越界了,此时进行调整,方法为i++。

        (2)超过最右列的位置(即j==n),如图1(b)所示,19填写好后,下一个数20的计算位置越界了,此时进行调整,方法为i+=2、j--。

        一种特例,在如图1(c)所示的4阶方阵中,10填写好后,下一个数11的计算位置,行和列都越界了,其处理方法同列越界,因此在程序中应先处理j==n的情况,再处理i==-1的情况。这样对于这种特例,由于处理了j==n后,i加了2,不会越界,因此不会再处理i==-1的情况。

        斜向下填写时,也会出现两种情况:

        (1)超过最左列的位置(即j==-1),如图1(d)所示,6填写好后,下一个数7的计算位置越界了,此时进行调整,方法为j++。

        (2)超过了底行的位置(即 i==n),如图1(e)所示,22填写好后,下一个数23的计算位置越界了,此时进行调整,方法为 i--,j+=2。

        一种特例,15填写好后,下一个数16的计算位置,行和列都越界了,但处理方法同行越界,因此在程序中应先处理i==n的情况,再处理j==-1的情况。这样对于这种特例,由于处理了i==n后,j加了2,不会越界,因此不会再处理j==-1的情况。

        每次进行越界调整填数后,填数的方向也会发生变化。因此,可设置一个方向变量up,当up=1时,表示斜向下填数;up=0时,表示斜向上填数。

        初始化时,令up=1、i=0、j=0;在当前位置填上1(即a[i][j]=1),之后从 m=2开始进行循环,直到m==n*n,全部n*n个数填写完毕。循环中,总是先按up的方向,确定下一个位置,然后填上相应的数。

        (6)源程序3。

#include <stdio.h>
#define  N  20
int main()
{
    int a[N][N];
    int n,i,j,m;
    scanf("%d",&n);
    int up=1;
    i=0;     j=0;
    a[i][j]=1;
    m=2;      // m是要填入的自然数
    while (m<=n*n)
    {
        if (up) { i++;  j--; }         // 从右上到左下
        else    { i--;  j++; }         // 从左下到右上
        if (j==n)                      // 超过最右列的位置
        {    i=i+2; j--;   up=!up;  }
        if (i==-1)                    // 超过首行的位置
        {    i++;   up=!up;    }
        if (i==n)                     // 超过底行的位置
        {   i--;   j+=2; up=!up; }
        if (j==-1)                    // 超过最左列的位置
        {    j++;    up=!up;   }
        a[i][j]=m++;
    }
    for (i=0;i<n;i++)
    {
        for (j=0;j<n;j++)
            printf("%4d",a[i][j]);
        printf("\n");
    }
    return 0;
}

有关“蛇形”方阵的构造的更多相关文章

  1. ruby - 我如何从 Rational(或任何没有构造函数的类)继承? - 2

    例如,我可以很容易地继承自String,如下所示:classMyString'thingsandstuff'但是我如何继承没有构造函数的Rational呢?例如:defMyRatNoMethodError:undefinedmethod`new'forMyRat:ClassMyRat(10).inc#=>NoMethodError:undefinedmethod`MyRat'formain:ObjectMyRat.send(:initialize,10).inc#=>TypeError:alreadyinitializedclass#???#Noneofitworks!我找不到初始化新

  2. ruby - 这种类似哈希/树状的构造称为什么? - 2

    我想创建一个介于散列和树之间的“Config”类。它只是用于存储全局值,可以有一个上下文。下面是我的使用方法:Config.get("root.parent.child_b")#=>"value"类可能如下所示:classConstructdefget(path)#splitpathby"."#searchtreefornodesenddefset(key,value)#splitpathby"."#createtreenodeifnecessary#settreevalueenddeftree{:root=>{:parent=>{:child_a=>"value",:child_b=

  3. ruby - 将构造函数参数转换为实例变量 - 2

    这个问题在这里已经有了答案:关闭11年前。PossibleDuplicate:Idiomaticobjectcreationinruby很多时候我有一个initialize方法,看起来像这样:classFoodefinitializebar,buz,...@bar,@buz,...=bar,buz,...endend有没有办法用一个简单的命令来做到这一点,比如:classFooattr_constructor:bar,:buz,...end其中的符号代表实例变量的名称(具有attr_accessor、attr_reader、attr_writer的精神/风格)?我想知道是否有内置的方式

  4. 通过传递构造函数的 Ruby YAML 解析器 - 2

    我正在开发一个应用程序,该应用程序从YAML文件获取输入,将它们解析为对象,然后让它们执行它们的操作。我现在遇到的唯一问题是YAML解析器似乎忽略了对象“初始化”方法。我指望构造函数用默认值填充YAML文件缺少的任何实例变量,并将一些东西存储在类变量中。这是一个例子:classTest@@counter=0definitialize(a,b)@a=a@b=b@a=29if@b==3@@counter+=1enddefself.how_manyp@@counterendattr_accessor:a,:bendrequire'YAML'a=Test.new(2,3)s=a.to_yaml

  5. Ruby 构造函数和异常 - 2

    Ruby新手,我想弄清楚使用什么习惯用法来将某些整数值限制为类的构造函数。根据我目前所做的,如果我在initialize()中引发异常,该对象仍会创建,但将处于无效状态(例如,某些nil实例变量中的值)。我不太明白我应该如何限制这些值而不进入看起来不必要的大步骤,例如限制对new()的访问。所以我的问题是,我可以通过什么机制来限制实例化对象的值范围? 最佳答案 嗯,你是完全正确的,即使initialize引发异常,对象仍然存在。然而,任何人都很难坚持引用,除非你从initialize中泄漏self就像我刚写的下面的代码一样:>>cl

  6. ruby-on-rails - 如何使用 Ruby 中哈希的查询参数构造 URI - 2

    如何通过传递哈希来构造带有查询参数的URI对象?我可以生成查询:URI::HTTPS.build(host:'example.com',query:"a=#{hash[:a]},b=#{[hash:b]}")产生https://example.com?a=argument1&b=argument2但是我认为为许多参数构造查询字符串将不可读且难以维护。我想通过传递哈希来构造查询字符串。就像下面的例子:hash={a:'argument1',b:'argument2'#...dozenmorearguments}URI::HTTPS.build(host:'example.com',que

  7. ruby - 如何更改 Ruby 中类构造函数的返回值? - 2

    我有课,Foo。我希望能够向构造函数传递一个Foo实例,foo并返回相同的实例。换句话说,我希望这个测试通过:classFoo;endfoo=Foo.newbar=Foo.new(foo)assert_equalfoo,bar有人知道我该怎么做吗?我试过这个:classFoodefinitialize(arg=nil)returnargifargendendfoo=Foo.newbar=Foo.new(foo)assert_equalfoo,bar#=>fails但它不起作用。帮忙吗?编辑因为很多人问过我的理由:我正在对大量数据(许多TB)进行快速分析,并且我将拥有大量对象的大量实例。

  8. ruby-on-rails - 文字和构造函数之间的区别? ([] 与 Array.new 和 {} 与 Hash.new) - 2

    我很想知道[]和Array.new以及{}和Hash.new之间的更多区别我对它进行了相同的基准测试,似乎简写是赢家require'benchmark'many=500000Benchmark.bmdo|b|b.report("[]\t"){many.times{[].object_id}}b.report("Array.new\t"){many.times{Array.new.object_id}}b.report("{}\t"){many.times{{}.object_id}}b.report("Hash.new\t"){many.times{Hash.new.object_id

  9. ruby - 构造函数覆盖 - 2

    我有一个类:classOnedefinitialize;endend我需要像这样用我自己的构造函数创建一个新类:classTwo但是当我启动代码时,出现错误:thingtest.rb:10:in`initialize':wrongnumberofarguments(1for0)(ArgumentError) 最佳答案 super在这种情况下(没有括号)是一种特殊形式。它使用原始参数调用父类(superclass)方法。尝试调用super() 关于ruby-构造函数覆盖,我们在StackO

  10. ruby - 在 ruby​​ 中调用父构造函数 - 2

    如何调用父类的构造函数?moduleCattr_accessor:c,:ccdefinitializationc,cc@c,@cc=c,ccendendclassBattr_accessor:b,:bbdefinitializationb,bb@b,@bb=b,bbendendclassA谢谢。 最佳答案 Ruby没有构造函数,因此显然不可能调用它们,无论是父类还是其他。然而,Ruby确实有方法,并且为了调用与当前正在执行的方法同名的父方法,您可以使用super关键字。[注意:不带参数的super是传递与当前正在执行的方法相同的参数

随机推荐