18.3.14(NBUOJ)

1156 简单一维数组排序

//不知道为什么文章格式有点乱,不太好调整,写的时候跟发出去后不太一样,是从word文档里面粘过来的原因么?

  • 思路:看过我上一次代码的小朋友们这题应该会觉得非常easy吧~最后一个数据的后面不需要空格,直接加换行符,那就可以把最后一个数字放在循环外。你们的数据量真的非常小呢,才10个,其实给我1e5个也ok的呀,如果只会简单排序的话,1e4个也行呢~
  • 代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
//(C++就是用C写的,所以两种代码长的差不多,机械专业不学,但是有兴趣的可以了解一下噢~)


int main(){
    int score[15];
    for(int i=0;i<10;i++){
        scanf("%d",&score[i]);
    }
    
    for(int i=0;i<9;i++){
        for(int j=i;j<10;j++){
            if(score[i]<score[j])
                swap(score[i],score[j]);
        }
    }
    
    for(int i=0;i<9;i++){
        printf("%d ",score[i]);
    }
    printf("%d\n",score[9]);
    return 0;
}

1262 无重复的排序

  • 思路1:排序,把相同的数据去掉,然后输出
  • 思路2:排序,输出的时候如果发现重复就不输出
  • 思路3:∵每个数据都大于0且小于100,∴技巧同上次的1005,从1100循环一遍就好
 
  • 思路1代码:
int delete(int s[],int n){//返回剩余个数
	int i,j,temp;
	for(j=0;j<n;j++){//排序
		for(i=j+1;i<n;i++){
			if(s[j]>s[i]){
				temp=s[i];
				s[i]=s[j];
				s[j]=temp;
			}
		}
	}
	for(i=n-2;i>=0;i--){//倒着删除挪动的数字会少一些
		if(s[i]==s[i+1]){
			for(j=i;j<n;j++){
				s[j]=s[j+1];
			}
			n--;
		}
	}
	return n;
}


int main(){
	int a[25],i,k;
	i=0;
	while(scanf("%d",&a[i])&&a[i]!=0){//输入
		i++;
	}
	k=delete(a,i);//处理
	for(i=0;i<k;i++)//输出
		printf("%d\n",a[i]);
	return 0;
}

  • 思路2代码(比思路1耗时长,内存消耗少一点)
//排序略,输出部分:
	for(i=0;i<n;i++){
        if(i==0 || te != data[i])
            printf("%d\n",data[i]);
        te=data[i];
	}

  • 思路3代码:(以后就不再写这种技巧的代码了呦)
        int data[105]={0};
	int te,i;
	while(scanf("%d",&te) && te!=0){
		data[te]++;
	}

	for(i=1;i<101;i++){
        if(data[i])
            printf("%d\n",i);
	}

1161 二维数组的最大值

  • 思路1:常规思路你们懂的,略
  • 思路2:虽说题目名字是二维数组,但是只让你找一个最大值,题目还贴心地直接告诉你是12个数,所以直接边输入边找最大值就好了。
 
  • 思路2代码(同种技巧将不再重复):
	int Max,i,te;
	for(i=0;i<12;i++){
        scanf("%d",&te);
        if(0 == i || te>Max)
/*小tip:这里0 == i是为了防止自己少写个=,把数字和变量反过来编译器就能检查到你这样的错误啦*/
            Max=te;
	}

       printf("%d\n",Max);

1140 单位矩阵初始化

  • 思路1:这题真的很简单,只要根据咱们OJ前几页题目的经验,开个足够大的二维数组,清零,然后一个循环让对角线变成1,最后输出就好了。
  • 思路2:干脆不要数组了,直接输出。
 
  • 思路1代码:
	int data[105][105]={0};
	int n,i,j;
	scanf("%d",&n);
	for(i=0;i<n;i++){
        data[i][i]=1;
	}
	for(i=0;i<n;i++){
        for(j=0;j<n;j++)
            printf("%d ",data[i][j]);
        printf("\n");
	}

思路2代码:

	scanf("%d",&n);
	for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            if(i==j) printf("1 ");
            else printf("0 ");
        }
        printf("\n");
	}

1142 二维数组求行平均值

  • 思路1:先存储,再循环、计算,代码略
  • 思路2:条件1:数组大小已知;条件2:阶数非常小;结论:可以每输3个数计算一下,存到一维数组里面(降维),然后输出。或者由于条件2,直接开三个ave存一下也行。
 
  • 思路2代码:(举降维的例子,开三个ave麻烦一点但同理)
	double sum[5]={0};
	int te,i;
	for(i=0;i<9;i++){
        scanf("%d",&te);
        sum[i/3]+=te;
	}

	for(i=0;i<3;i++){
        printf("%.1f\n",sum[i]/3);
	}

1164 对角线元素和

  • 思路1
  • 思路2:只求主对角线,还是最简单的和,∴又可以偷懒了。宁大OJ,很贴心。
 
  • 思路2代码(这种偷懒技巧将不再重复):
    	sum=0;
        scanf("%d",&n);
	for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            scanf("%d",&te);
            if(i == j)
                sum+=te;
        }
	}

        printf("%d\n",sum);

1298 上三角置零

  • 思路1:输入、处理、输出3
  • 思路2:输入、输出时加判断,if i<j输出0else输出存储的数据

 代码略


1299 内部和

  • 思路1:略
  • 思路2:技巧同 1002二维数组的最大值 ,输入时加判断(判断不在边界上)求和

代码略


1312 边界积

  • 思路1:先求四个边界积,再分别除掉每个边界第一个或最后一个值(或者最后一个根本就不要乘进去)。
  • 思路2:遍历数组,用判断语句确定是否要乘当前值。
 
  • 思路1代码:
	__int64 product,row1,rown,col1,coln;
    int data[15][15];
    int m,n,i,j;
    product=1;
    row1=rown=1;
    col1=coln=1;

    scanf("%d%d",&m,&n);
    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            scanf("%d",&data[i][j]);
        }
    }

    if(m==1 || n==1){//如果只有一行或者一列
        for(i=0;i<m;i++){
            for(j=0;j<n;j++){
                product*=data[i][j];
            }
        }
    }
    else{
        for(i=0;i<m-1;i++){//最后一行(属于rown)没有乘进去
            col1*=data[i][0];
            coln*=data[i][n-1];
        }
        for(j=0;j<n;j++){
            row1*=data[0][j];
            rown*=data[m-1][j];
        }
        row1/=data[0][0]*data[0][n-1];
    }
    product*=row1*col1*rown*coln;

printf("%I64d\n",product);

  • 思路2代码:
    long long product;
    int data[15][15];
    int m,n,i,j;
    product=1;

    scanf("%d%d",&m,&n);
    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            scanf("%d",&data[i][j]);
        }
    }


    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            if(i==0 || i==m-1 || j==0 || j==n-1){
                product*=data[i][j];
            }
        }
    }

    printf("%lld\n",product);

1162 二维数组最大值及位置

  • 思路1:常规标记思路略
  • 思路2:∵给定数组的维数,∴可以利用取模的特性偷懒
 
  • 思路2代码:
	int Max,max_i,i,te;
	for(i=0;i<12;i++){
        scanf("%d",&te);
        if(i==0 || Max<te){
            Max=te;
            max_i=i;
        }
	}
        printf("%d %d %d\n",Max,max_i/4,max_i%4);

1165 杨辉三角形

思路:n<=15了,那么就不好用数学公式(含阶乘的)求解啦,所以我们还是用二维数组好了(对公式感兴趣的自行百度吧)。

代码:

	int n,i,j;
        int Yanghui[20][20]={1};//相当于第一个赋值1,其余清零
	scanf("%d",&n);
	for(i=1;i<n;i++){
        Yanghui[i][0]=1;
		for(j=1;j<=i;j++){
			Yanghui[i][j]=Yanghui[i-1][j]+Yanghui[i-1][j-1];
		}
	}
	for(i=0;i<n;i++){
		for(j=0;j<=i;j++){
			printf("%d ",Yanghui[i][j]);
		}
		printf("\n");
	}

1181 二维数组的鞍点

  • 思路1:先找到第x行中最大值所在列,这一行刚好是此列中最小的的话,这就是个鞍点。
  • 思路2:记录下每行的最大值所在的列数,每列最小值所在行数。最后遍历 每行找到的列数,那么第i行“最大值所在列”(这是个列数)的“最小值所在行”(这是个行数)刚好是i的话,我们就找到了鞍点。
 
  • 思路1核心代码:
        X=-1;
	while(x++<n-1){
/* x++<n-1这地方如果基础知识不扎实,可能会有点懵逼,不过不影响,继续看的话大意你们应该看得懂 */
		y=0;
		for(i=1;i<m;i++)
			if(a[x][i]>a[x][y]) y=i;//找到第x行最大数所在的列,赋给y
		for(i=0;i<n;i++)
			if(a[i][y]<a[x][y]) break;
//判断这个最大的数是不是所在列中最小的数,不是就会break掉
		if(i==n){
			if(flag==0||Min>a[x][y]) Min=a[x][y];//还没找到过或者碰到更小的,则更新Min
			flag=1;
		}
	}


	if(flag)
		printf("%d\n",Min);
	else
		printf("not exist\n");

  • 思路2核心代码:
	int data[105][105],x[105]={0},y[105]={0};
/* x代表第i行的最大值所在的列数,y代表最第i列最小值所在行数 */
        flag=0;

	scanf("%d%d",&n,&m);
	for(i=0;i<n;i++)
		for(j=0;j<m;j++){
			scanf("%d",&data[i][j]);
			if(data[i][j] > data[i][ x[i] ]) x[i]=j;
            if(data[i][j] < data[ y[j] ][j]) y[j]=i;
		}

	for(i=0;i<n;i++){
            if( y[ x[i] ] == i && (flag == 0 || Min>data[i][ x[i] ]) ){
                Min=data[i][ x[i] ];
                flag=1;
            }
	}

小结:

       1. 看到一些小朋友不太会用scope,也就是这个: { } 。举个例子,for(...)后面如果不加花括号,那么它只能管到一个语句。也就是它后面那一句。如果你想多管几句,那一定不要忘了把这几句都加进 { } 里来。当然如果for里面有if-else语句,就可以管到两句以上了,那是因为if-else语句是一个整体,for不会管了if却抛弃else的。

       2. 1003那个题没有给出数据范围,所以很多小朋友都开了1000*1000大小的数组,但是呢,据我的经验,1e5的大小还能在main函数内开出来,影响不大,1e6就要崩了。所以你们也会发现出现了上次题解中我提到的忘记写&会出现的那个对话框。这时候有两种解决办法。

            a) 开小一点,反正咱们OJ前几页题目测试的数据量不会太大。

            b) 可以把数组移到main函数外面,把它从 局部变量 变成 全局变量。这个你们还没学,往后学了就清楚啦~有兴趣的可以去预习噢~

        3. 1006那题就发现有小朋友把你们学过的对齐给忘掉了呀!看表格,为什么以第1个格不存在呢?你可以想象如果用0填补不是可能直接导致扩大了好几倍嘛?注意如果数字位数超过对齐位数,是会把数字全部显示的噢!如果很好地理解了我的上一次题解中用到的技巧,10061007应该都不成问题的哦!

对齐方式(例如4位对齐)

左对齐

右对齐

多余位0填补

不存在的

%04d

多余位空格填补

%-4d

%4d

        4. 1008边界积这个题呢,其实挺简单的,但是我看大家好像都不会用__int64。要注意的是这里的“_”是两个,写一个是会报错的呦。还有就是输入输出格式,会变成%I64d。如果你用的是用思路1,一定要注意,测试数据给的很大,刚好卡住了__int64的范围,所以一定要先做除法再做乘法,不然会爆__int64(也就是超出__int64能表示的范围),你可能会看到一个你想不通的数字,可能会是负数,这就是“上溢”。看到有小朋友错了很多次,大概就是这两个缘故了。最后强势推荐CB,因为你可以看到如下图所示这样的效果。并且我设置的字体和大小都是我觉得比较舒服的。关键字颜色也很清爽。


        5. 给你们一个小技巧。一些小朋友已经会右键标题栏->编辑->粘贴了,但是一些小朋友还在手输。如果你们右键标题栏点了属性,会出现下面这样一个界面(我一般用CB,所以以CB为例)选中快速编辑模式,复制好内容以后右键就可以粘贴了。VC++6.0差不多一样的。


        6. 其他的一些小问题就比如有时候某台电脑的VC++会出现莫名其妙的问题,这个时候不要忘了你的电脑上还有codeblocks或者C-free,都可以试试。这两次我已经遇到三只小朋友出现这个问题了。尤其是进门第三列靠窗东侧前两台机子比较爱出这个问题,不过我还不太明白原因。

        7. 大多小朋友的代码还是非常整齐干净的,不过也有一些小朋友的代码可读性实在有点不如意。你们可以参考我给出的代码,看一下怎样对齐,对清晰美观的代码有个概念。我写代码也时常偷懒,比如判断里和for循环条件里省掉几个空格啥的。但是程序大致的结构还算清晰。包括考虑一下为什么我会花那么多时间把一个可以用很短一个字母代替的变量写成productmin_iscore这样的名字呢?就是为了让你们一眼能看明白它的意思。不然如果没有注释,过一段时间你可能就难以看懂自己的代码了,别人看起来也会相对比较费劲。写出可读性强的干净整洁的代码,是一个好习惯!

        8. 最后,发现有小朋友拿着一本答案在抄噢!不会做的话,也有很多办法的,比如现在你可以对照一下我给的思路跟代码,看看自己是因为基本知识欠缺还是思路匮乏导致的不会呢?然后,有针对性地解决问题,如果是没有什么思路,我能想到的有两个问题,a.你对知识点的运用还生疏着;b.你可能没休息好。如果归因于a,这时候可以找找你的小伙伴让他给你点提示之类的,也许会获得一些启发,把题目做出来。

 

        3.18补充:课下又看到一个问题,就是有的小朋友用了嵌套循环,但是外层用了i,内层也用了i,这样做是很容易造成死循环的噢!如果一个循环用了i,循环内部最好不要去改变i,除非你能确定你的思路是没有问题的,不会造成死循环的,需要这样做的情况本身就非常少,所以这一般都需要很好的逻辑能力噢~















  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值