第22次 CCF CSP认证一二题题解及感悟

第22次 CCF CSP认证一二题题解及感悟

    • 第一题灰度直方图
      • 题目重述
      • 题目分析
      • 代码及注释(C++)
    • 第二题邻域均值
      • 题目重述
      • 题目分析
      • 代码及注释(C++)
      • 感悟

第一题灰度直方图

题目重述

一幅长宽分别为 n 个像素和 m 个像素的灰度图像可以表示为一个 n×m 大小的矩阵 A。

其中每个元素 Aij(0≤i

具体来说,一个 8 比特的灰度图像中每个像素的灰度范围是 [0,256)。

一副灰度图像的灰度统计直方图(以下简称“直方图”)可以表示为一个长度为 L 的数组 h,其中 h[x](0≤x

显然,h[0] 到 h[L−1] 的总和应等于图像中的像素总数 n⋅m。

已知一副图像的灰度矩阵 A,试计算其灰度直方图 h[0],h[1],⋯,h[L−1]。

输入格式
输入共 n+1 行。

输入的第一行包含三个用空格分隔的正整数 n、m 和 L,含义如前文所述。

第二到第 n+1 行输入矩阵 A。第 i+2(0≤i

输出格式
输出仅一行,包含用空格分隔的 L 个整数 h[0],h[1],⋯,h[L−1],表示输入图像的灰度直方图。

数据范围
0 4≤L≤256
输入样例1:
4 4 16
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
输出样例1:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

题目分析

简单来说,第一题是用来统计一个矩阵中数值相等的点的个数,不同数值的点构成一个数组,数组中存储各个数值的点的个数,最终输出该数组即可

代码及注释(C++)

#include
#include
#include

using namespace std;

const int N = 510, M=510, L=266;

int n,m,l;
int h[L];//灰度值个数数组 
int s[N][N];//矩阵数组
 
int main()
{
	cin>>n>>m>>l;
	for(int i=0;i<n;i++)//三重循环,输入矩阵后进行统计
	{
		for(int j=0;j<m;j++)
		{
			cin>>s[i][j];
			for(int k=0;k<l;k++)		
		    {
		    	if(s[i][j]==k)
		    	h[k]++;
			}
		}	  
	}
		
	for(int i=0;i<l;i++) printf("%d ",h[i]);
	return 0;
}

第二题邻域均值

题目重述

顿顿在学习了数字图像处理后,想要对手上的一副灰度图像进行降噪处理。

不过该图像仅在较暗区域有很多噪点,如果贸然对全图进行降噪,会在抹去噪点的同时也模糊了原有图像。

因此顿顿打算先使用邻域均值来判断一个像素是否处于较暗区域,然后仅对处于较暗区域的像素进行降噪处理。

待处理的灰度图像长宽皆为 n 个像素,可以表示为一个 n×n 大小的矩阵 A,其中每个元素是一个 [0,L) 范围内的整数,表示对应位置像素的灰度值。

对于矩阵中任意一个元素 Aij(0≤i,j

Neighbor(i,j,r)={Axy|0≤x,y
这里使用了一个额外的参数 r 来指明 Aij 附近元素的具体范围。

根据定义,易知 Neighbor(i,j,r) 最多有 (2r+1)2 个元素。

如果元素 Aij 邻域中所有元素的平均值小于或等于一个给定的阈值 t,我们就认为该元素对应位置的像素处于较暗区域。

现给定邻域参数 r 和阈值 t,试统计输入灰度图像中有多少像素处于较暗区域。

输入格式
输入共 n+1 行。

输入的第一行包含四个用空格分隔的正整数 n、L、r 和 t,含义如前文所述。

第二到第 n+1 行输入矩阵 A。第 i+2(0≤i

输出格式
输出一个整数,表示输入灰度图像中处于较暗区域的像素总数。

数据范围
70% 的测试数据满足 n≤100、r≤10。
全部的测试数据满足 0

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

题目分析

题目定义了一个邻域,统计元素aij周围一个区域内的元素总和,再除以元素个数与阈值t比较,若小于等于t,则证明元素aij处于较暗区域,最终计算出较暗区域点的个数。

领域中元素个数最多为(2r+1)2,当领域左上角(x1,y1)或邻域右下角(x2,y2)超出边界时元素个数小于(2r+1)2,需要用(x2-x1+1)*(y2-y1+1)计算元素个数。

计算一个矩阵中子矩阵的部分可以使用前缀和,或者叫部分和。一维前缀和容易理解,如已知数组a[N],数组和s[N],求a3,a4,…,a10的和,利用前缀和计算:s[10]-s[2]。

本题使用二维前缀和,计算如图所示矩形面积,左上角坐标为(x1,y1),右下角坐标为(x2,y2),s[i][j]表示第i行j列格子左上部分所有元素的和,故所求面积为
s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]

第22次 CCF CSP认证一二题题解及感悟_第1张图片

代码及注释(C++)

#include
#include
#include

using namespace std;

const int N = 610;

int n,l,r,t;
int a[N][N];//矩阵数组
int s[N][N];//二维前缀和数组

int main()
{
	cin>>n>>l>>r>>t;
	for(int i=0;i<n;i++)
	 for(int j=0;j<n;j++)
	 {
	 	cin>>a[i][j];
	 	s[i][j]=a[i][j]+s[i-1][j]+s[i][j-1]-s[i-1][j-1];//计算前缀和
	 }	
	
	int res=0; 
	for(int i=0;i<n;i++)
	 for(int j=0;j<n;j++)
	 {
	 	int x1=max(0,i-r), y1=max(0,j-r);
	 	int x2=min(n-1,i+r), y2=min(n-1,j+r);
	 	int sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
	 	int cnt=(x2-x1+1)*(y2-y1+1);
	 	if(sum<=t*cnt)//sum/cnt可能产生小数,故将cnt与t相乘
	 	 res++;
	 }
	 
	cout<<res;
	return 0;
} 

感悟

去年12月份我第一次考csp,只做出了第一题,说实话并不意外甚至是超常发挥,因为准备时间很短,连大一C语言的基础知识都忘记了;第二次是今年4月份,买了acwing的csp辅导课,看y总的直播课,感觉提高还是很多的,但是正式考试的时候老毛病又犯了,紧张到大脑停止思考,我觉得可能第一题都做不出来了,挣扎了快一个小时,终于做出来了,第二题有几个样例都通过了,但是没得分,这次的判分很严格,最终结果是和第一次一样的成绩,排名甚至到80%了。等到考试结束,听y总讲完,其实也没这么难。

说实话,csp前两题不难,多刷题就ok,第三题大模拟难度不大,但是很庞杂,细节很多,这次的dhcp服务器跟着y总的视频敲了一遍,之后自己看着题目又复盘了一次,考试估计很难做出来。

考csp的初衷是想免考研机试,顺便加点综测,开始刷题的时候觉得很难,难以下手,知识点很多,不知道怎么准备,也很迷茫,想过放弃。

考过两次之后,心态有变化了,就算最后考不到300分以上,也不会有遗憾了,毕竟在这个过程中,自己有了很多提高。希望下次更好,考个好分数 ,加油!

你可能感兴趣的:(算法,csp)