大疆机试(2022/8/7)

这篇博客介绍了三种不同的算法方法——BFS、并查集和DFS,用于在二维像素矩阵中找出与指定像素点颜色相似的区域。通过设定灰度值差值阈值,遍历并连接相邻的相似像素,计算出选区的点坐标个数。样例输入和输出展示了算法的正确性和效率,提示了在解决此类问题时需要注意递归可能导致的堆栈溢出问题。
摘要由CSDN通过智能技术生成

题目

很多修图软件提供了类似于魔法棒的功能,当你点选一个像素的时候,会同时帮你把附近相似颜色的像素摘取出来形成一个选区。其背后的简单逻辑是根据你选择的像素点向外扩充(上下左右),当相邻像素和被选中的像素存在相似的时候就选上,并继续向外扩充判断。
先拟定判断相似的条件为像素点的灰度值与被选的点差值在阈值以内(不包含阈值)的判断其为相似像素。
一个像素点的灰度值根据unit8_t类型来表示,以下面的二维数组为例子:

38 182 36 37 38 39
40 54 206 140 38 40
36 40 243 181 39 94
38 36 196 37 239 38
37 38 25 38 36 39

假设阈值为3,被选中的像素点坐标为4,1(标红数据,左上角为原点,从0开始,x方向指向右,y方向指向下),则被筛选出的区域合集(标绿部分及被选点本身)为(2,0),(3,0),(4,0),(4,1),(4,2),(5,0),(5,1)

现要求阈值,被选中的坐标和图像数据作为参数进行输入,输出被选择的选区的点坐标个数

输入描述

第一行输入五个整数N,M,X,Y,T(N和M均大于0且小于等于1000),以空格隔开,N为该二维数组的行数,M为该二维数组的列数,X和Y为坐标(X>=0且X<N,Y>0且Y<M),T为阈值(T>=0且T<=255)
接下来N行,每行都有M格数字,为图像的数据,数值范围为[0,255]

输出描述

输出被选择的选区的点坐标个数

样例输入

6 6 2 3 3
37 37 39 41 13 205
37 41 41 203 39 243
37 41 40 131 40 41
91 41 39 198 41 9
189 41 39 40 40 38
37 124 38 167 41 41

样例输出

24

提示
若采用递归的解法需要考虑堆栈是否可能溢出

解析:

方法一:BFS

#include <iostream>
using namespace std;
#include <queue>
#include <vector>

class Solution {
public:
	int findNumOfLink(vector<vector<int>>& grid, int x, int y, int T) {
		int ans = 0;
		int m = grid.size(), n = grid[0].size();
		int d[4][2] = { {0,1}, {1,0}, {0,-1},{-1,0} };
		queue<int> q;
		vector<bool> visited(m * n, false);
		q.push(x * n + y);
		visited[x * n + y] = true;
		while (!q.empty()) {
			int sz = q.size();
			for (int i = 0; i < sz; i++) {
				int cur = q.front();
				int curX = cur / n;
				int curY = cur % n;
				q.pop();
				ans++;
				for (int k = 0; k < 4; k++) {
					int nextX = curX + d[k][0];
					int nextY = curY + d[k][1];
					if (nextX >= 0 && nextX < m && nextY >= 0 && nextY < n
						&& !visited[nextX * n + nextY] && abs(grid[nextX][nextY] - grid[x][y]) < T) {
						q.push(nextX * n + nextY);
						visited[nextX * n + nextY] = true;
					}
				}
			}
		}
		return ans;
	}
};

int main() {
	int N, M, X, Y, T;
	cin >> N >> M >> X >> Y >> T;
	vector<vector<int>> grid(N, vector<int>(M));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			cin >> grid[i][j];
		}
	}
	Solution solve;
	int ans = solve.findNumOfLink(grid, Y, X, T);
	cout << ans << endl;

	return 0;
}

方法二:并查集

#include <iostream>
using namespace std;
#include <vector>

class UF {
public:
	int count;
	vector<int> parent;
	vector<int> size;

	UF(int n) {
		count = n;
		parent.resize(n);
		size.resize(n);
		for (int i = 0; i < n; i++) {
			parent[i] = i;
			size[i] = 1;
		}
	}

	void Union(int p, int q) {
		int rootP = find(p);
		int rootQ = find(q);
		if (rootP == rootQ) {
			return;
		}

		if (size[rootP] < size[rootQ]) {
			parent[rootP] = rootQ;
			size[rootQ] += size[rootP];
		}
		else {
			parent[rootQ] = rootP;
			size[rootP] += size[rootQ];
		}
		count--;
	}

	bool connected(int p, int q) {
		int rootP = find(p);
		int rootQ = find(q);
		return rootP == rootQ;
	}

	int find(int x) {
		while (parent[x] != x) {
			parent[x] = parent[parent[x]];
			x = parent[x];
		}
		return x;
	}
};

class Solution {
public:
	int findNumOfLink(vector<vector<int>>& grid, int x, int y, int T) {
		int ans = 0;
		int m = grid.size(), n = grid[0].size();
		int d[4][2] = { {0,1}, {1,0}, {0,-1},{-1,0} };
		UF* uf = new UF(m * n);
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				if (abs(grid[i][j] - grid[x][y]) >= T) {
					continue;
				}
				for (int k = 0; k < 4; k++) {
					int nextX = i + d[k][0];
					int nextY = j + d[k][1];
					if (nextX >= 0 && nextX < m && nextY >= 0 && nextY < n
						&& abs(grid[nextX][nextY] - grid[x][y]) < T ) {
						//cout << grid[nextX][nextY] << "--"<< grid[x][y] << endl;
						uf->Union(i * n + j, nextX * n + nextY);
					}
				}
			}
		}
		int p = uf->parent[x * n + y];	
		return uf->size[p];
	}
};

int main() {
	int N, M, X, Y, T;
	cin >> N >> M >> X >> Y >> T;
	vector<vector<int>> grid(N, vector<int>(M));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			cin >> grid[i][j];
		}
	}
	Solution solve;
	int ans = solve.findNumOfLink(grid, Y, X, T);
	cout << ans << endl;

	return 0;
}

方法三:DFS

#include <iostream>
using namespace std;
#include <vector>

class Solution {
public:
	int chooce = 0;
	int ans = 0;
	int findNumOfLink(vector<vector<int>>& grid, int x, int y, int T) {
		this->chooce = grid[x][y];
		vector<bool> visited(grid.size() * grid[0].size(), false);
		dfs(grid, x, y, T, visited);
		return ans;
	}

	void dfs(vector<vector<int>>& grid, int i, int j, int T, vector<bool> &visited) {
		int m = grid.size(), n = grid[0].size();
		if (i < 0 || i >= m || j < 0 || j >= n){
			return;
		}
		if (visited[i * n + j] || abs(grid[i][j] - chooce) >= T) {
			return;
		}
		ans++;
		visited[i * n + j] = true;
		dfs(grid, i + 1, j, T, visited);
		dfs(grid, i - 1, j, T, visited);
		dfs(grid, i, j + 1, T, visited);
		dfs(grid, i, j - 1, T, visited);
	}
};

int main() {
	int N, M, X, Y, T;
	cin >> N >> M >> X >> Y >> T;
	vector<vector<int>> grid(N, vector<int>(M));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			cin >> grid[i][j];
		}
	}
	Solution solve;
	int ans = solve.findNumOfLink(grid, Y, X, T);
	cout << ans << endl;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值