1068 万绿丛中一点红 (20 分)

1068 万绿丛中一点红 (20 分)

题意描述:
对于计算机而言,颜色不过是像素点对应的一个 24 位的数值。现给定一幅分辨率为 M×N 的画,要求你找出万绿丛中的一点红,即有独一无二颜色的那个像素点,并且该点的颜色与其周围 8 个相邻像素的颜色差充分大。

输入格式:
输入第一行给出三个正整数,分别是 M 和 N(≤ 1000),即图像的分辨率;以及 TOL,是所求像素点与相邻点的颜色差阈值,色差超过 TOL 的点才被考虑。随后 N 行,每行给出 M 个像素的颜色值,范围在 [0,2^​24​​ ) 内。所有同行数字间用空格或 TAB 分开。

输出格式:
在一行中按照 (x, y): color 的格式输出所求像素点的位置以及颜色值,其中位置 x 和 y 分别是该像素在图像矩阵中的列、行编号(从 1 开始编号)。如果这样的点不唯一,则输出 Not Unique;如果这样的点不存在,则输出 Not Exist。

输入样例 1:

8 6 200
0 	 0 	  0 	   0	    0 	     0 	      0        0
65280 	 65280    65280    16711479 65280    65280    65280    65280
16711479 65280    65280    65280    16711680 65280    65280    65280
65280 	 65280    65280    65280    65280    65280    165280   165280
65280 	 65280 	  16777015 65280    65280    165280   65480    165280
16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215

输出样例 1:

(5, 3): 16711680

输入样例 2:

4 5 2
0 0 0 0
0 0 3 0
0 0 0 0
0 5 0 0
0 0 0 0

输出样例 2:

Not Unique

输入样例 3:

3 3 5
1 2 3
3 4 5
5 6 7

输出样例 3:

Not Exist

解题思路:

Bob: 这道题有点意思哈,像是那种考图算法的样子,其实又不是。
Bob: (读题中…) 其实就是遍历一个二维数组,找到其中满足条件的元素。
Bob: 嗯,对,就是这样,就是条件有点问题。一个条件是“独一无二”,那应该是说这个元素在整个二维数组里只出现了一次。第二个条件是说,这个元素周围要有8个元素和它的像素差大于tol,这就有点问题了。是所有8个差值都大于tol呢?还是8个差值的平均值大于tol呢?如果差值是负数怎么办?还有边界情况下不满足8个点怎么办??
Bob: 有点烦这种题目,讲又不讲清楚,还得自己去试,说不定还得看别人的博客。
Alice: 你啥都想好了就去做呗,大不了wrong answer呗。
Bob: 说不定还要 tle (time limit exceed)超时。
Alice: 嗯呢,好的。
Bob: (╯︵╰)


代码:

  • Python Version: (测试点4超时)
def main():
    M, N, TOL = (int(x) for x in input().split())
    # 输入M,N,TOL,存储为整数
    data = []
    # 用来存储输入的像素矩阵
    not_tol = [[0 for x in range(M)] for z in range(N)]
    # 用来记录tol不满足的像素点,矩阵形状和data相同,not_tol[i][j] == 1表示坐标i,j的像素点不满足tol条件。
    unique_numbers = {}
    # 记录每个像素值出现的次数
    for x in range(N):
        temp = []
        for y in input().split():
            y = int(y)
            unique_numbers.setdefault(y, 0)
            unique_numbers[y] += 1
            # 记录每个像素值出现的次数
            temp.extend([y])
        data.extend([temp])
        # 记录整个像素值矩阵到data
    directions = [(-1, -1), (0, -1), (1, -1), (1, 0),
                  (1, 1), (0, 1), (-1, 1), (-1, 0)]
    # 记录一个像素点周围的8个方向
    total = 0
    answer = []
    # 记录满足条件的像素点的个数和他们的位置

    for x in range(N):
        for y in range(M):
            # 遍历整个像素点矩阵
            if unique_numbers[data[x][y]] == 1 and not_tol[x][y] == 0:
                # 如果该像素点的值仅出现过一次,而且可能满足tol条件
                count = 0
                # 记录该像素点周围与其满足tol条件的点的个数
                for direction in directions:
                    # 遍历周围的8个点
                    tempx = x + direction[0]
                    tempy = y + direction[1]
                    if tempx >= 0 and tempx < N and tempy >= 0 and tempy < M:
                        # 非边界情况
                        if abs(data[x][y] - data[tempx][tempy]) > TOL:
                            # 满足tol条件
                            count += 1
                        else:
                            # 不满足tol条件,此时两个点都已经不可能是“独一无二”的像素点了。
                            not_tol[tempx][tempy] = 1
                            not_tol[x][y] = 1
                            # 无需继续搜索,已经被拒绝了,直接break。
                            break
                    else:
                        if abs(data[x][y] - 0) > TOL:
                        # 边界情况,假装周围有一圈零,算一算得了。
                            count += 1
                if count == 8:
                    #对于每一个像素点,如果周围有8个点和它满足tol关系
                    total += 1
                    answer.append((x, y))
                if total >= 2:
                    # 有至少两个点满足答案要求,根据题意是not unique,可以退出了。
                    break
                    
    # 根据题意输出答案,这里没有用到total,可惜了。
    if len(answer) == 0:
        print("Not Exist")
    elif len(answer) == 1:
        print("({}, {}): {}".format(answer[0][1] + 1, answer[
              0][0] + 1, data[answer[0][0]][answer[0][1]]))
        # 注意这里,数组的下标是从0开始的,题目中的下标是从1开始的。
    else:
        print("Not Unique")
        # for x in answer:
        #     print("({}, {}): {}".format(x[0], x[1], data[x[0]][x[1]]))


if __name__ == '__main__':
    main()
  • C++ Version:
#include <math.h>
#include <stdio.h>
#include <iostream>
using namespace std;

#define max_color_value 16777216 + 10   // 定义最大像素值,2^24 == 16777216
#define max_col_row 1000 + 10           // 定义像素矩阵的宽高最大值
int value_cnt[max_color_value];         // 二维数组,记录每个像素值出现的次数
int data[max_col_row][max_col_row];     // 二维数组,记录输入的像素矩阵


int main(void){
	
	// 声明变量并读入数据
	int M;
	int N;
	int TOL;
	scanf("%d %d %d", &M, &N, &TOL);
	for(int i=0; i<N; ++i){
		for(int j=0; j<M; ++j){
			scanf("%d", &data[i][j]);
			value_cnt[data[i][j]] += 1;  //记录每个像素值出现的次数
		}
	}
	int directions[8][2] = {{-1, -1},{0, -1},{1, -1}, {1, 0},
	                        {1, 1},{0, 1}, {-1, 1}, {-1, 0}};   //二维矩阵,记录8个方向
    int total = 0;  // 满足题目中要求的像素点个数
    int answer[2];  // 满足题目中要求的最后一个像素点的坐标,没必要把所有满足要求的像素点的坐标都记录下来。
    for(int x=0; x<N; ++x){
    	for(int y=0; y<M; ++y){
    		if(value_cnt[data[x][y]] > 1){   // 一个像素点不是 “独一无二”的
    			continue;
    		}
    		int count = 0;                  // 记录该像素点周围有多少点与其满足tol条件
    		int tempx;
    		int tempy;
    		for(int dre_idx=0; dre_idx < 8; ++dre_idx){ // 遍历周围的8个点
    			tempx = x + directions[dre_idx][0];
    			tempy = y + directions[dre_idx][1];
    			if(tempx >= 0 && tempx < N && tempy >= 0 && tempy < M){  // 非边界情况
    				if(abs(data[x][y] - data[tempx][tempy]) > TOL){      // 满足tol条件
    					count += 1;
    				}else{
    					break;
    				}
    			}else{                                                  // 边界情况
    				if(abs(data[x][y] - 0) > TOL){                      // 满足tol条件
    					count += 1;
    				}else{
    				    break;
    				}
    				
    			}    				
    		}
    		if(count == 8){                                            // 周围有8个点和其满足tol关系,记录坐标,答案数加一
    			total += 1;
    			answer[0] = x;
    			answer[1] = y;
    		}
    		if(total > 1){                                            // 根据题意,有多余一个像素点满足要求,直接退出即可。
    			break;
    		}
    	}
    }
    // 根据题目要求,输出“万绿丛中一点红”的情况
    if(total == 0){
    	printf("Not Exist\n");
    }else if(total == 1){
    	printf("(%d, %d): %d\n", answer[1] + 1, answer[0] + 1, data[answer[0]][answer[1]]);   // 注意下标
    }else{
    	printf("Not Unique\n");
    }
	
	return 0;
} 

易错点:

  • 1 独一无二的像素点意味着这个像素值在整幅图像里只出现了一次。
  • 2 “并且该点的颜色与其周围 8 个相邻像素的颜色差充分大。” 这里与周围8个相邻像素要考虑到图像边界的情况,对于处于图像边界周围相邻像素少于8个的,用0填充满8个。如下图所示:填充
    需要注意的是,这里必须在相邻像素少于8个的时候用0填充到8个,如果只计算周围的相邻像素不能得到正确结果。如上图中,计算左上角的点的时候,如果只计算相邻的3个像素点是无法得出正确结果的。

总结:

  • 用python刷题容易超时,除非是时间复杂度能得到较大的提升,否则一般的优化还是容易超时。

python_chaoshi


  • C++虽然写起来费劲,跑起来还是很快的。
    C++ok
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值