【数组】洛谷题目记录

目录

幻方

冰雹猜想

显示屏

珠心算测验

Bovine Bones G

开灯

蛇形填阵

杨辉三角

MC:插火把

压缩技术

压缩技术(续集版)

方块转换


幻方

P2615

思路:输入--->填数--->输出幻方

           可以确定第一个数字1所填的位置,将1填入以后可以根据1的位置推出2的位置,由2的位置推出3的位置,依此类推,可以推到n*n的位置;当所填的数字超过n*n的时候可以结束循环。

简单地码亿下:

#include<stdio.h>
#include<string.h>

int main()
{
    int n,kase = 2;
    scanf("%d",&n);
    int a[n][n];
    memset(a,0,sizeof(a));
    int x = 0,y = (n-1)/2;
    a[x][y] = 1;
    while(kase<=n*n){
        if(x==0&&y!=n-1){
            x = n - 1;
            a[x][++y] = kase++;
        }
        else if(x&&y==n-1){
            y = 0;
            a[--x][y] = kase++;
        }
        else if(x==0&&y==n-1)
            a[++x][y] = kase++;
        else if(x&&y!=n-1&&a[x-1][y+1]==0)
            a[--x][++y]=kase++;
        else if(x&&y!=n-1&&a[x-1][y+1]!=0)
            a[++x][y]=kase++;
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(!j)  printf("%d",a[i][j]);
            else    printf(" %d",a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

PS:通过++x、++y、kase++等可以实现先移动再填数或者先填数再实现k+1,从而增强代码可读性。


冰雹猜想

P5727

思路:只需要将每次操作得到的数字储存起来之后进行逆序输出即可,因此可以将其存到一个数组里面。将输入的n作为数组的第一个元素,根据n的奇偶得到新的数字作为下一个元素,依此类推直到将1存入数组(可以记下此时1存到了数组里的第几号元素)。最后只需要从1开始逆序输出。

所以,这个菜鸟写了代码如下:

#include<stdio.h>
int a[2000];
int main()
{
int n,kase=0,remind=0;
scanf("%d",&n);
    a[0]=n;
for(int i=1;i<2000;i++){
    if(n==1){
        a[i]=n;
        break;
    }
    if(n%2!=0)
        n=3*n+1;
        else
            n/=2;
    a[i]=n;
    kase++;
}
for(int j=kase;j>=0;j--){
    if(remind)
        printf(" %d",a[j]);
    else{
        printf("%d",a[j]);
        remind=1;
    }
}
    return 0;
}

显示屏

P5730

思路:第二行输入可以存到字符串里,使用的时候从最左边开始读取。显示屏上每个数字占据5行3列,每两个数字中间由一列 ' . ',于是可以考虑开辟二维数组,用这个数组充当显示屏,每读取一个数字就显示一个数字。那么可以通过一个计数器指向最左边的第0列,每显示一个数字就右移四列,这样每次只需要操作计数器指向的那一列及其右侧两列即可。

头脑风暴之后,写了代码如下:

#include<stdio.h>
#include<string.h>

int main()
{
    int n,kase = 0;
    scanf("%d",&n);
    int num[5][4*n-1];
    char a[n+1];
    scanf("%s",a);
    memset(num,'X',sizeof(num));
    初始化“显示屏”
    for(int i=0;i<5;i++){
        for(int j=3;j<4*n-1;j+=4)
            num[i][j] = '.';
    }
    让显示屏显示数字
    for(int i=0;a[i]!='\0';i++){
        if(a[i]=='0')
            num[1][kase+1] = num[2][kase+1] = num[3][kase+1] = '.';
        else if(a[i]=='1'){
            for(int j=kase;j<=kase+1;j++){
                for(int k=0;k<5;k++)
                    num[k][j] = '.';
            }
        }
        else if(a[i]=='2'){
            num[1][kase] = num[1][kase+1] =num[3][kase+1] =num[3][kase+2] = '.';
        }
        else if(a[i]=='3'){
            for(int j=1;j<5;j+=2)
                for(int k=kase;k<=kase+1;k++)
                    num[j][k] = '.';
        }
        else if(a[i]=='4'){
            num[0][kase+1] = num[1][kase+1] = '.';
            for(int j=3;j<5;j++)
                for(int k=kase;k<=kase+1;k++)
                    num[j][k] = '.';
        }
        else if(a[i]=='5'){
            num[1][kase+2] = num[1][kase+1] =num[3][kase] =num[3][kase+1] = '.';
        }
        else if(a[i]=='6'){
            num[1][kase+1] = num[1][kase+2] = num[3][kase+1] = '.';
        }
        else if(a[i]=='7'){
            for(int j=1;j<5;j++){
                for(int k=kase;k<=kase+1;k++)
                    num[j][k] = '.';
            }
        }
        else if(a[i]=='8'){
            num[1][kase+1] = num[3][kase+1] = '.';
        }
        else if(a[i]=='9'){
            num[3][kase] = num[3][kase+1] = num[1][kase+1] = '.';
        }
        kase+=4;
    }
    /输出
    for(int i=0;i<5;i++){
        for(int j=0;j<4*n-1;j++)
            printf("%c",num[i][j]);
            printf("\n");
    }
    return 0;
}

PS:输出的时候用%c,这样可以把存储的字符的ASCLL码(数字)转化输出为对应的字符。每个数字对应不同情况,进入分支(我觉得一定还有我没有想到的更好的显示数字的方法QWQ)


珠心算测验

P2141

思路:将数字输入到数组中里面,每次都选出不同的两个数字求和,再将和与数组中的其他数字一一比对即可。

误区:求的和不能重复,比如1+4=5,2+3=5,但是5只能算一次;1+4与4+1也只算一组。

于是可以写一段长长的die码:

#include<stdio.h>
#include<string.h>
int kase = 0;
int judge(int d[],int t,int n){
    for(int i =0;i<n;i++){
        if(d[i]==t)    return 0;
    }
    return 1;
}

int main()
{
    int n,t,kase = 0;
    scanf("%d",&n);
    int a[n],d[n];
    memset(d,0,sizeof(d));
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=0;i<n-1;i++){
        for(int j=i+1;j<n;j++){
            t = a[i] + a[j];
            for(int k = 0;k<n;k++){
                if(a[k]==t&&judge(d,t,n)){
                    //printf("%d.%d + %d = %d\n",kase+1,a[i],a[j],a[k]);
                    d[kase] = t;
                    kase++;
                }
            }
        }
    }
    printf("%d",kase);
    return 0;
}

PS:当找到一组满足题意的时候,只需要把求的和存到另一个数组中,每次只需要再将求和与该数组中的元素比较,均不相同的时候才计数加一。


Bovine Bones G

P2911
P2911

思路:三层循环计算总和,用桶排序处理。最小的情况是3,最大到80。

因此:

#include<stdio.h>

int main()
{
    int s1,s2,s3;
    int min,kase = 3;
    int a[81] = {0};
    scanf("%d%d%d",&s1,&s2,&s3);
    for(int i=1;i<=s1;i++){
        for(int j=1;j<=s2;j++){
            for(int k=1;k<=s3;k++){
                a[i+j+k]++;
            }
        }
    }
    min = a[3];
    for(int i=3;i<=80;i++){
        if(min<a[i]){
            min = a[i];
            kase = i;
        }
    }
    printf("%d",kase);
    return 0;
}

开灯

P1161
P1161

 思路:最多对2000000盏灯操作,可以开辟数组。假定开灯状态为1,关灯为0,则先使该数组内元素均为0;每当进行一次操作,就使对应的元素由1变为0或由0变为1;最后只需要遍历数组,找到1就可以输出编号。

#include<stdio.h>

int s[2000005] = {0};

void light(double a,int t){
    for(int i=1;i<=t;i++){
        int m = i*a;
        if(s[m]==0)   s[m] = 1;
        else if(s[m]==1)   s[m] = 0;
    }
}

int main()
{
    int x,t,i;
    double a;
    scanf("%d",&x);
    for(i = 0;i<x;i++){
        scanf("%lf%d",&a,&t);
        light(a,t);
    }
    for(i = 1;s[i]==0;i++);
    printf("%d",i);
    return 0;
}

蛇形填阵

P5731

思路:开辟一个全为0的数组,从左上角开始填,那么第一个数字一定是1。外层通过循环控制填一圈数字,用每次填入的数字做判定条件即可。填数字的规律一定为先向右,然后经过判断转向下后填数,依次向左、向上填完每一圈。那么转弯的条件便可以是:未到达边界且将要填数的位置上为0。

#include<stdio.h>
#include<string.h>

int main()
{
    int n,x = 0,y = 0;
    scanf("%d",&n);
    int a[n][n],t = 2;
    memset(a,0,sizeof(a));
    a[0][0] = 1;
    while(t<=n*n){
        while(y<n-1&&!a[x][y+1])    a[x][++y] = t++;
        while(x<n-1&&!a[x+1][y])    a[++x][y] = t++;
        while(y>0&&!a[x][y-1])      a[x][--y] = t++;
        while(x>0&&!a[x-1][y])       a[--x][y] = t++;
    }
    for(int i = 0;i<n;i++){
        for(int j = 0;j<n;j++)
            printf("%3d",a[i][j]);
        if(i!=n-1)
            printf("\n");
    }
    return 0;
}

PS:看资料说x、y、a[0][0]的赋值操作合并为一句: a[x=0][y=0] = 1

                                                                   (o.O)


杨辉三角

P5732

思路:输出为三角形,只需要内层把变量循环到与外层循环变量一样就可以。两侧均为1,从第三行开始每个数字都等于该数字上方和左上方的数字之和。

#include<stdio.h>

int main()
{
    int n;
    scanf("%d",&n);
    int a[n][n];
    for(int i=0;i<n;i++){
        a[i][0] = a[i][i] = 1;
    }
    for(int i=2;i<n;i++){
        for(int j=1;j<i;j++){
            a[i][j] = a[i-1][j-1] + a[i-1][j];
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<=i;j++){
            if(!j)    printf("%d",a[i][j]);
            else        printf(" %d",a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

MC:插火把

P1789

思路:首先需要开辟n*n的方阵,认为没有光亮和方块的地方为0,有光照或方块为1。个人认为如果直接对原方阵操作,那么需要考虑萤石火把找到的范围内有没有越界的情况,那么就需要对火把萤石的位置进行分支操作,较为麻烦。于是想到,可以开辟(n+4)*(n+4)的方阵,而原先开辟的方阵相当于处于正中间的n*n的方阵((0,0)相当于此时的(2,2),(n,n)相当于此时的(n+2,n+2)),这样,无论火把萤石在什么地方,光照范围都不会越界,而真正需要统计的只是中间方阵里面的0的数目,外圈就不需要考虑了。

所以:

#include<stdio.h>
#include<string.h>

int main()
{
    int n,m,k,kase = 0;
    scanf("%d%d%d",&n,&m,&k);
    int a[n+4][n+4],x,y;
    memset(a,0,sizeof(a));
    //火把
    for(int i = 0;i<m;i++){
        scanf("%d%d",&x,&y);
        x = x + 1;
        y = y + 1;
        //点亮环境
        a[x+1][y+1] = a[x-1][y-1] = a[x+1][y-1] = a[x-1][y+1] = 1;
        for(int j = x-2;j<=x+2;j++)
            a[j][y] = 1;
        for(int j = y-2;j<=y+2;j++)
            a[x][j] = 1;
    }
    //萤石
    for(int i = 0;i<k;i++){
        scanf("%d%d",&x,&y);
        x = x + 1;
        y = y + 1;
        //点亮环境
        for(int j = x-2;j<=x+2;j++){
            for(int t = y-2;t<=y+2;t++)
                a[j][t] = 1;
        }
    }
    for(int i = 2;i<=n+1;i++){
        for(int j = 2;j<=n+1;j++)
            if(a[i][j]==0)
                kase++;
    }
    printf("%d",kase);
    return 0;
}

压缩技术

P1319

思路:开辟数组之后,可以让x=0、y=0,之后每输入一个数就进行一次填数操作,再通过对a[x][y]赋值进行填数(每当y=n的时候就转到下一行第一个开始填数),再实现填0和1交替进行就可以得到题目要求的点阵。最后输出就可以。

​
#include<stdio.h>

int main()
{
    int n,t,kase = 0,m = 1,x,y;
    scanf("%d",&n);
    int a[n][n];
    x = y = 0;
    while(kase!=n*n){
        scanf("%d",&t);
        kase+=t;
        //确定填1或0
        if(m==0)    m = 1;
        else        m = 0;
        //依次填数
        for(int i = 0;i<t;i++){
            a[x][y] = m;
            y++;
            if(y==n){
                y = 0;
                x++;
            }
        }
    }
    //输出点阵
    for(int i = 0;i<n;i++){
        for(int j = 0;j<n;j++)
            printf("%d",a[i][j]);
        printf("\n");
    }
    return 0;
}

​

​

当然,可以首先把所有的元素都赋为0,这样只需要填1就可以,大体思路是差不多的(m的初始值为0):

while(kase<n*n){
    scanf("%d",&t);
    kase+=t;
    //确定填1
    if(m==0){
        m = 1;
        x+=t/n;
        y+=t%n;
        continue;
    }
    else{
        //依次填1
        for(int i = 0;i<t;i++){
            a[x][y++] = m;
            if(y==n){
                y = 0;
                x++;
            }
        }
        m = 0;
    }
}

压缩技术(续集版)

P1320

思路:首先输入点阵,那么需要用二维的字符数组来输入储存。这样, 每个位置都对应一个数字,只需要确定该数字是否连续相同、相同多少次就可以。在每次判断之后立刻输出次数即可。

#include<stdio.h>

int main()
{
    char str[205][205];
    int t = 0,N,i,j,kase1 = 0,kase2 = 0;
    while(scanf("%s",str[t++])!=EOF);
    printf("%d",t-1);
    if(str[0][0]=='1')  printf(" 0");
    for(i = 0;i<=t;i++){
        for(j = 0;j<=t;j++){
            if(str[i][j]=='0'){
                if(kase2)    printf(" %d",kase2);
                kase1+=1;
                kase2 = 0;
            }
            else if(str[i][j]=='1'){
                if(kase1)   printf(" %d",kase1);
                kase1 = 0;
                kase2+=1;
            }
        }
    }
    kase1?printf(" %d",kase1):printf(" %d",kase2);
    return 0;
}

每次都是发生数值变化的时候才输出之前统计的结果,输出之后就可以将其清零并统计当前数字的连续次数。通过判断kase1、kase2是否为零可以确定是否发生了数值变化。


方块转换

P1205

思路:用字符串数组输入,然后找出每一种情况下坐标对应关系,依次判断就可以。

不用自定义函数的话可以写这么一坨:

#include<stdio.h>

int main()
{
    int n,kase = 0;
    scanf("%d",&n);
    char a[n+1][n+1],b[n+1][n+1],c[n+1][n+1];
    for(int i = 0;i<n;i++)
        scanf("%s",a[i]);
    for(int i = 0;i<n;i++)
        scanf("%s",b[i]);
    for(int i = 0;i<n;i++){
        for(int j = 0;j<n;j++)
            c[i][n-1-j]=a[i][j];
    }

    while(1){
//方法一
        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++)
                if(a[i][j]!=b[j][n-1-i])
                    kase++;
        }
        if(!kase){
            printf("1");
            break;
        }
        kase = 0;
//方法二
        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++)
                if(a[i][j]!=b[n-1-i][n-1-j])
                    kase++;
        }
        if(!kase){
            printf("2");
            break;
        }
        kase = 0;
//方法三
        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++)
                if(a[i][j]!=b[n-1-j][i])
                    kase++;
        }
        if(!kase){
            printf("3");
            break;
        }
        kase = 0;
//方法四
        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++)
                if(a[i][j]!=b[i][n-1-j])
                    kase++;
        }
        if(!kase){
            printf("4");
            break;
        }
        kase = 0;
//方法五
    //方法一
        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++)
                if(c[i][j]!=b[j][n-1-i])
                    kase++;
        }
        if(!kase){
            printf("5");
            break;
        }
        kase = 0;
    //方法二
        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++)
                if(c[i][j]!=b[n-1-i][n-1-j])
                    kase++;
        }
        if(!kase){
            printf("5");
            break;
        }
        kase = 0;
    //方法三
        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++)
                if(c[i][j]!=b[n-1-j][i])
                    kase++;
        }
        if(!kase){
            printf("5");
            break;
        }
        kase = 0;
//方法六
        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++)
                if(a[i][j]!=b[i][j])
                    kase++;
        }
        if(!kase){
            printf("6");
            break;
        }
        printf("7");
        break;
    }
    return 0;
}

也可以把每一部分单独摘出来写成函数:每当发现不一样的两个元素就return 0,如果完全一样则在最后return 1。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值