1068 万绿丛中一点红 (20 point(s))

// 16 points
#include <bits/stdc++.h>
using namespace std;

struct Loction{
	int i, j;
};

int main() {
	// N行 M列  图像 分辨率 TOL 所求像素点与相邻点的颜色差阈值
	int m, n, TOL;
	vector<Loction> loc;
	cin >> m >> n >> TOL;
	 
	// 定义多两行 便于边界处进行差值计算 
	int pixel[n + 2][m + 2] = {0}; 	
	// 初始化边界为 -1 便于判断而不会计算边界
	fill(*pixel, *pixel + (m + 2) * (n + 2), -1);

	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			cin >> pixel[i][j];
			
	// 筛选阈值以上的像素点 
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			if(pixel[i][j] > TOL)
				loc.push_back({i, j});
				
	// 独一无二颜色 与其周围 8 个相邻像素的颜色差充分大
	// 遍历阈值以上坐标点 获得与周围的颜色差并用 map 记录
	map<long, int> unique; 
	map<long, Loction> uniLoc; 
	for(auto l: loc){
		// 忘记初始化
		long sum = 0;
		// 获取左上角坐标为起始行下标和列下标 
		for(int i = l.i - 1; i <= l.i + 1; i++){
			for(int j = l.j - 1; j <= l.j + 1; j++){
				// 如果不为边界并且超过阈值计算周围像素点的差值(取绝对值 
				if(pixel[i][j] > TOL) sum += abs(pixel[i][j] - pixel[l.i][l.j]); 
			}
		}
		// 记录当前像素点差值 个数 对应差值的下标 
		unique[sum]++;
		uniLoc[sum] = {l.i, l.j};
	} 
	
	if(unique.rbegin()->second != 1) cout<< uniLoc[unique.rbegin()->first].i << uniLoc[unique.rbegin()->first].j << "Not Unique";
	// (j, i)列 行(x, y): color 格式 所求像素点 位置 及颜色值
	else{
		// 获取颜色和坐标 
		int col = unique.rbegin()->first;
		Loction l = uniLoc[col];
		printf("(%d, %d): %d", l.j, l.i, pixel[l.i][l.j]);
	} 
}
// 20 points
#include <bits/stdc++.h>
using namespace std;

struct Loction{
	int i, j;
};

// N行 M列  图像 分辨率 TOL 所求像素点与相邻点的颜色差阈值
int m, n, TOL, cnt = 0, x, y;
// 定义多两行 便于边界处进行差值计算 
int pixel[1000 + 2][1000 + 2]; 

// 检查阈值
bool check(int i, int j) {
	// 获取左上角坐标为起始行下标和列下标 
	for(int x = i - 1; x <= i + 1; x++){
		for(int y = j - 1; y <= j + 1; y++){
			// 跳过中间 
			if(x == i && y == j) continue;
			// 超过阈值不属于要计算的点
			if(abs(pixel[x][y] - pixel[i][j]) <= TOL) return false;
		}
	} 
	return true;
}

int main() {
	vector<Loction> loc;
	map<int, int> vis;
	cin >> m >> n >> TOL;
	 
	// 初始化边界为 -1 便于判断而不会计算边界
	fill(*pixel, *pixel + (1000 + 2) * (1000 + 2), -1);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++){
			cin >> pixel[i][j];
			vis[pixel[i][j]]++;
		}
			
	// 筛选颜色唯一的像素点 并且与其周围 8 个相邻像素的颜色差充分大
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			if(vis[pixel[i][j]] == 1 && check(i, j)){
				cnt++;
				x = j, y = i;
			}
				
	// 点不存在(相差不充分大 Not Exist
	if(cnt == 0) {cout << "Not Exist";}
	// 点不唯一 Not Unique
	else if(cnt == 1) {printf("(%d, %d): %d", x, y, pixel[y][x]);}
	// (j, i)列 行(x, y): color 格式 所求像素点 位置 及颜色值
	else{cout << "Not Unique";}  
}

开始的时候没看清到底 M 和 N 那个是行那个是列,导致行列颠倒而矩阵转置了。就输入来说 N 是行 M 是列,跟平时输入时候的习惯是相反的。但是读题的时候没注意,直接就扫过去了,便按照平时的意识来读取行列的数据。所以后面调试的时候打印出来才发现数据的位置不对劲。

还有一个就是定义 sum 和的时候忘记每次循环的时候初始化了,导致每次最大都是最后一个位置(右下角)。所以以后定义和这种变量的时候,要有意识初始化。或者记得,如果找最大值的时候发现不论什么数据结果都是遍历的最后一个的话,就可能是忘记把 变量和 初始化话了,导致结果都堆在最后一个变量上,导致其最大。


当时没想明白怎么判断相差不充分大这个条件,所以直接提交得16分。

但实际忽略了题目条件,基于错误的思路必然难以满足条件,统计出唯一点个数。

独一无二颜色的那个像素点

这句话当时以为只是一个背景介绍,没想到是要充当条件的。去掉颜色的话就是 “独一无二的像素点” 再翻译一下颜色变成数值,就是找所有数据中只出现过一次的点。

TOL,是所求像素点与相邻点的颜色差阈值,色差超过 TOL 的点才被考虑

这句话当时也没有认真考虑,所以忽略了这个条件,写出了错误的思路。TOL描述的对象是要被处理的点及其相邻的点,两者一起才构成阈值,而后面说的超过TOL才被考虑,说的是与这个被处理点与周围的色差都要满足超过TOL的条件,否则任一个不满足,那么被处理的点就不是唯一点。而当时写出错误代码的时候是考虑到这个条件的。

最近很多都是没能够理解清楚题意,不能够明确题目的真正意思。可能对待题目的条件过于表面了,没能够拐一点弯,转换下题目理解的方向,或者尝试深入拆解下题目的描述。

就比如第一个错误理解的句子,看起来这个“独一无二颜色”只是一个对于背景的描述,但同样要看到后面有一个明确指代的对象“像素点”,这是本题需要解决的重点对象,所以不可能平白无故说这么轻飘飘一句话。就得在后面写出执行方法的时候,对这个描述有所考虑。

还有第二个句子没有正确理解。说明没有具体明确句子描述的内容,没有搞清楚里面出现了几个对象,具有什么关系。扫一眼走个过场就不管了,后面错了也是很正常。


这样原本的代码就需要删掉许多不必要的计算和标记,同时更改某些处理方式。比如原本判断八个方向是把中间也算在里面的,现在用别人的方法,就不能判断中间了,因为中间相减后 == 0 必然小于阈值TOL。所以要跳过中间。

if(x == i && y == j) continue;

不然可以用别人的方法,定义八个方向的坐标偏移值在数组中,然后调用与当前中间的坐标加减运算。

step[8][2] = { {1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1} };

int xx = x + step[i][0], yy = y + step[i][1];

还有关于检查阈值的判断,因为需要 true 和 false 的结果,所以将这个检查的行为抽象成一个函数放在主函数外当成另一个函数,,只需要把要检查的点的坐标传入进去。

bool check(int i, int j) {
	// 获取左上角坐标为起始行下标和列下标 
	for(int x = i - 1; x <= i + 1; x++){
		for(int y = j - 1; y <= j + 1; y++){
			// 跳过中间 
			if(x == i && y == j) continue;
			// 超过阈值不属于要计算的点
			if(abs(pixel[x][y] - pixel[i][j]) <= TOL) return false;
		}
	} 
	return true;
}

因为当时定义的是随着输入的行列而动态变化的数组,所以难以将数组传给函数,普通的方法需要在函数的参数类型中定义确定的行和列,显然动态的没法给出一个明确的参数。

当然也找到另外一个方法,可以通过传入数组首地址的方式,函数中使用的时候也可以用 [] 来指向元素,不过在定义和初始化的时候要麻烦,要对每一行新建列对象。

向函数传递一个二维数组(指针传递)

如此,还不如直接在函数之外定义一个满足题目要求的大数组,只需要明确遍历的范围即可。初始化用一个 fill() 。

int pixel[1000 + 2][1000 + 2];

参考代码

posted on 2021-09-08 07:59  Atl212  阅读(37)  评论(0)    收藏  举报

导航