日常记录——关于数组下标计算的一点心得

最近在 伟大的LG 的指导下开始玩了玩URAL的新手村,虽然说是非常简单的,但是还是遇到了一点小小的问题,卡住了进度。
在URAL的新手村里,竟然有一种题型出现了两次,那就是关于数组下标的计算,分别是URAL1319和1313。

先说说1313吧,这道题大概就是先输入一个数n,表示将有一个n*n的矩形,然后再给你这个矩形,让你按一种顺序输出。
这个顺序很好找,直接看样例就晓得了。

样例输入:
4
1 3 6 10
2 5 9 13
4 8 12 15
7 11 14 16
样例输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

很显然吧。
(要是觉得不显然,那就把你的脑袋逆时针旋转45°,然后你就发现了)
什么都不管,先输入了再说

for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)
        cin>>a[i][j];

那么我们继续~
但是,看是很好看出来,但是怎么处理呢?
其实,就是一个简单的模拟过程而已。
把脑袋旋转之后,你会发现,前n行每行的数字个数和行数是一样的,那么,我们关于那半边的循环语句就已经很好写了(不要告诉我你不打算用循环写)

for(i=1;i<=n;i++)
    for(j=1;j<=i;j++)
        cout<<a[A][B].........

这个很简单是吧?但是,我们怎么才能正确的输出呢?
准确的说,现在问题就转换成关于i和j的控制了。

可以发现,我们偏着脑袋看时,每一行的开始部分其实在我们正着脑袋看时,都相较于上一次往下走了一行,也就是说,我们的A和i是成正比的,但是,随着j的变化,我们的位置又是会一直往上走的,那么,这就是在告诉我们,A和j是成反比的。
所以,在A这个和式里,绝对有一个i-j出现。

那么,A到底是什么呢?看看前后的边界条件,猜一猜就好了啦~(其实是可以找出来的,比如本人,当然也不是很复杂,并不是我体会的重点,就不再赘述了)。
其实A已经算的差不多了,只是在减的时候会减重一位,所以,我们最终的A是A=i-j+1

现在,我们来玩玩神奇的B这个和式吧~
神奇的发现,在偏着脑袋看时,每一行的开始位置在原来的矩形中都是第一列的!!也就是说,i的变化其实是和B无关的!
那么再继续考虑j,其实也不用考虑,你会神奇的发现当前位置的列数就是从第一列开始,然后到当前的第i列结束,所以,我们的B就很简单了:B=j

现在开始玩玩剩下的那一坨东西~一样的分析方法,还是继续旋转你的脑袋吧~当然,考虑到现在你看的前n行已经可以算出来了,所以自行用你的想象力去掉吧~

那么,剩下的那个东西其实比较有趣的(和一开始那个其实是比较相似的~)

嘿嘿嘿,具体发现的规律真的比较相似,那么,迭代i和j的循环语句直接摆上来就可以看懂了

for(i=n-1;i;i--)
    for(j=1;j<=i;j++)
        cout<<a[A][B]..............

很显然吧~
那么,我们再使用这种神奇的方法来计算啦~
在你脑袋逆时针旋转45°之后,会发现,每一行的开始位置在原来的那个矩形里面,都是从最后一行开始的!!!也就是说,A式里绝对有一个n出现,并且是没有i的!那么,我们再继续考虑j吧,在j增大的同时,当前的行是不断在上升的(也就是A的值在减小),所以说,A里绝对有一个-j的存在,然后,再考虑到相减会减重一个项,所以+1就好了呢~
所以,现在我们的A就计算出来了呢:A=n-j+1很神奇吧~

再来B这个和式~还是通用的分析方法,在你斜着脑袋看时,每一个开始位置在原来矩形中的列数是随着i的减小而增大的,所以,B中一定有一个-i的存在。然后,i是从n-1开始的,所以B中还一定有一个n(想想为什么)!!!那么,随着j的增大,我们的列数也是在增大的,所以B中一定有一个j。
那么,B就如此愉快的算出来了~~B=n-i+j

好了,在把我完整的代码贴一遍吧~~

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int a[110][110];
int main() {
    int i,j,k,m,n;
    cin>>n;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            cin>>a[i][j];
    int cnt=0;
    for(i=1;i<=n;i++)
        for(j=1;j<=i;j++){
            cout<<a[i-j+1][j];
            if(++cnt<n*n)cout<<" ";
        }
    for(i=n-1;i;i--)
        for(j=1;j<=i;j++){
            cout<<a[n-j+1][n-i+j];
            if(++cnt<n*n)cout<<" ";
        }
    cout<<endl;
    return 0;
}

神奇的是,在继续刷的时候我竟然还碰到了1319这么相似的题目,直接看样例,秒懂是在干什么:

样例输入:
3
样例输出:
4 2 1
7 5 3
9 8 6

懂了?(这次是把你的脑袋顺时针旋转45°)

相同的分析方法,就直接上代码了:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int a[110][110];
int main() {
    int i,j,k,m,n;
    cin>>n;
    int cnt=0;
    for(i=1;i<=n;i++)
        for(j=1;j<=i;j++)
            a[j][n-i+j]=++cnt;

    for(i=n-1;i;i--)
        for(j=1;j<=i;j++)
            a[n-i+j][j]=++cnt;

    for(i=1;i<=n;i++,cout<<endl){
        for(j=1;j<n;j++,cout<<" ")
            cout<<a[i][j];
        cout<<a[i][n];
    }

    return 0;
}

就到这里鱼块的结束了,有没有对大家有一点帮助呢?麻烦大家点个赞吧~哈哈,谢谢大家。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值