#P2891. 第1题-图像亮度坐标搜索
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 1742
            Accepted: 402
            Difficulty: 5
            
          
          
          
                       所属公司 : 
                              华为
                                
            
                        
              时间 :2025年4月23日-暑期实习
                              
                      
          
 
- 
                        算法标签>排序算法          
 
第1题-图像亮度坐标搜索
题解
题面描述
给定一张二维图像,图像中每个值表示该坐标下的亮度。现在给定一个亮度值 m,请返回离图像中心坐标最近的 k 个亮度为 m 的坐标 (x,y)。
题解思路
- 
坐标系和中心坐标计算
给定图像宽度 w 和高度 h,图像的中心坐标为 (2w−1,2h−1),这是我们计算距离时的参考点。 - 
遍历图像并找到亮度为 m 的点
d=∣x−2w−1∣+∣y−2h−1∣
对于每个点 (x,y),如果该点的亮度值为 m,则计算它与中心点的曼哈顿距离: - 
排序和选择
将所有亮度为 m 的点按距离中心的曼哈顿距离排序。若距离相同,则按 x 坐标排序,若 x 相同,再按 y 坐标排序。最后,选择距离最小的 k 个点。 - 
输出结果
输出排序后的前 k 个坐标。 
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);  // 加速输入输出
    cin.tie(nullptr);  // 解绑 cin 和 cout,进一步加速输入输出
    int w, h, m, k;
    cin >> w >> h;  // 输入图像的宽度和高度
    cin >> m;  // 输入目标亮度值
    cin >> k;  // 输入需要输出的坐标个数
    
    int cx = (w - 1) / 2, cy = (h - 1) / 2;  // 计算图像中心坐标
    
    vector<tuple<int, int, int>> v;  // 存储亮度为 m 的点(距离,x,y)
    v.reserve(w * (long long)h);  // 预先分配足够的空间,避免频繁扩容
    
    // 遍历图像的每个点
    for (int y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
            int b;
            cin >> b;  // 读取每个点的亮度值
            
            if (b == m) {  // 如果亮度值等于 m
                int d = abs(x - cx) + abs(y - cy);  // 计算该点到中心的曼哈顿距离
                v.emplace_back(d, x, y);  // 存储(距离,x,y)元组
            }
        }
    }
    
    int n = v.size(), t = min(k, n);  // 选择前 k 个点,若亮度为 m 的点少于 k 个,取实际数量
    
    // 自定义排序函数:首先按距离排序,其次按 x 坐标排序,最后按 y 坐标排序
    auto cmp = [](auto &a, auto &b) {
        if (get<0>(a) != get<0>(b)) return get<0>(a) < get<0>(b);  // 按距离排序
        if (get<1>(a) != get<1>(b)) return get<1>(a) < get<1>(b);  // 若距离相同,按 x 坐标排序
        return get<2>(a) < get<2>(b);  // 若距离和 x 坐标都相同,按 y 坐标排序
    };
    // 对亮度为 m 的点按距离、x、y 排序
    if (n > t) 
        partial_sort(v.begin(), v.begin() + t, v.end(), cmp);  // 如果有多于 k 个点,部分排序
    else 
        sort(v.begin(), v.end(), cmp);  // 否则对所有点进行排序
    // 输出结果,按照排序后的前 t 个点
    for (int i = 0; i < t; i++) {
        if (i) cout << ' ';  // 在每对坐标之间加空格
        cout << get<1>(v[i]) << ' ' << get<2>(v[i]);  // 输出每个坐标的 x 和 y
    }
    return 0;
}
Python
import sys
def main():
    # 读取输入数据
    data = sys.stdin.read().split()
    it = iter(data)
    
    # 图像的宽度、高度和亮度值
    w = int(next(it))
    h = int(next(it))
    m = int(next(it))
    k = int(next(it))
    
    # 计算图像中心坐标
    cx = (w - 1) // 2
    cy = (h - 1) // 2
    
    # 存储亮度为 m 的点和其距离
    pts = []
    
    # 遍历图像的每个点
    for y in range(h):
        for x in range(w):
            b = int(next(it))
            # 如果亮度值等于 m,则计算距离
            if b == m:
                d = abs(x - cx) + abs(y - cy)
                pts.append((d, x, y))
    
    # 按照(距离,x,y)排序
    pts.sort()
    
    # 输出结果,选择前 k 个坐标
    res = pts[:min(k, len(pts))]
    out = []
    for _, x, y in res:
        out.append(f"{x} {y}")
    sys.stdout.write(" ".join(out))
if __name__ == "__main__":
    main()
Java
import java.io.*;
import java.util.*;
public class Main {
    public static void main(String[] args) throws IOException {
        // 读取输入数据
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        // 图像的宽度、高度和亮度值
        int w = Integer.parseInt(st.nextToken());
        int h = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(br.readLine().trim());
        int k = Integer.parseInt(br.readLine().trim());
        
        // 计算图像中心坐标
        int cx = (w - 1) / 2;
        int cy = (h - 1) / 2;
        
        // 存储亮度为 m 的点和其距离
        List<int[]> pts = new ArrayList<>();
        
        // 遍历图像的每个点
        for (int y = 0; y < h; y++) {
            st = new StringTokenizer(br.readLine());
            for (int x = 0; x < w; x++) {
                int b = Integer.parseInt(st.nextToken());
                // 如果亮度值等于 m,则计算距离
                if (b == m) {
                    int d = Math.abs(x - cx) + Math.abs(y - cy);
                    pts.add(new int[]{d, x, y});
                }
            }
        }
        
        // 按照(距离,x,y)排序
        pts.sort(Comparator
            .comparingInt((int[] a) -> a[0])
            .thenComparingInt(a -> a[1])
            .thenComparingInt(a -> a[2])
        );
        
        // 输出结果,选择前 k 个坐标
        StringBuilder sb = new StringBuilder();
        int t = Math.min(k, pts.size());
        for (int i = 0; i < t; i++) {
            int[] p = pts.get(i);
            if (i > 0) sb.append(' ');
            sb.append(p[1]).append(' ').append(p[2]);
        }
        System.out.print(sb.toString());
    }
}
        题目内容
给定一张二维图像,图像中每个值表示该坐标下的亮度。现在给定一个亮度值 m ,请返回离图像中心坐标最近的 k 个亮度为 m 值的坐标 (x,y)。
提示:
1.图像中元素的坐标范围 x:[0,w−1],y:[0,h−1] 。
2.图像宽高 w,h 均为奇数,图像中心坐标 (w−1)/2,(h−1)/2 。
3.平面上两点之间的距离为 ∣x1−x2∣+∣y1−y2∣ 。
4.在距离相同的情况下,以 x 小的点优先;当 x 相同时,以 y 小的点优先。
5.题目可保证至少存在一个亮度值为 m 的点。
输入描述
第一行输入为图像宽度 w 和图像高度 h,以空格隔开,宽高范围为 1~ 2000
第二行输入为给定亮度值 m ,范围为 1 ~ 1000
第三行输入为需要输出的亮度值为 m 的坐标个数 k ,范围为 1 ~ 100 ,且 k<=w∗h
接下来共 h 行,每行内为 w 个亮度,以空格隔开,亮度范围为 1 ~ 1000
输出描述
按顺序输出坐标序列,坐标 x 和 y 以空格隔开,坐标间使用空格隔开如样例所示。
x,y 坐标均不相同时以 x 增序排列, 坐标相同时以 y 增序排列。若满足条件的坐标个数不足 k,则以实际坐标个数输出。
样例1
输入
5 5
10
3
10 2 3 4 5
1 2 3 4 10
1 2 3 10 5
1 10 3 4 5
1 2 3 4 5
输出
3 2 1 3 4 1
说明
该用例图像 w=5,h=5,给定亮度值 m=10 ,需要输出 m=10 的距离中心最近的 3 个坐标。
该图像中心坐标为 (2,2) 。
从图像中可以看出,距离中心坐标最近的 m=10 的坐标为 (3,2) ,距离为 ∣3−2∣+∣2−2∣=1 ;
距离第二近的坐标为 (1,3) ,距离为 ∣1−2∣+∣3−2∣=2 ;
距离第三近的坐标为 (4,1) ,距离为 ∣4−2∣+∣1−2∣=3 ;
由上可知,三个坐标为 (3,2)、(1,3)、(4,1),按照输出格式要求,输出为 3 2 1 3 4 1
样例2
输入
3 3
10
6
1 10 1
10 10 10
1 10 1
输出
1 1 0 1 1 0 1 2 2 1
说明
该用例图像 w=3,h=3,给定亮度值 m=10 ,需要输出 m=10 的距离中心最近的 6 个坐标。
该图像中心坐标为 (1,1) 。
从图像中可以看出,距离中心坐标最近的 m=10 的坐标为 (1,1) ,距离为 0 ;
剩余满足 m=10 的坐标有 4 个,分别为 (1,0)(0,1)(2,1)(1,2),距离均为 1 .
由输出规则 x,y 坐标均不相同时以 x 增序排列, x 坐标相同时以 y 增序排列,得到输出序列为 (1,1)(0,1)(1,0)(1,2)(2,1),满足条件的坐标为 5 个,不足输入中要求的 6 个,实际只需输入 5 个。
由上可知,输出为 1 1 0 1 1 0 1 2 2 1
提示
1.图像中元素的坐标范围 x:[0,w−1],y:[0,h−1] 。
2.图像宽高 w,h 均为奇数,图像中心坐标 (w−1)/2,(h−1)/2 。
3.、平面上两点之间的距离为 ∣x1−x2∣+∣y1−y2∣ 。
4.在距离相同的情况下,以 x 小的点优先;当 x 相同时,以 y 小的点优先。