MS Recognition

题目1 : MS Recognition

时间限制:30000ms

单点时限:3000ms

内存限制:256MB

描述

Given an image containing only two kinds of capital letters, 'M' and 'S', can you tell how many of each letter are there in the image? Note that the letters may be of different sizes and may be rotated.

输入

The first line contains two integers H and W, indicating the height and weight of the image.  (1 <= H, W <= 500)  

Then follows an H x W matrix indicating the image.

'.' indicates the pixel is empty and '#' indicates the pixel is part of a letter.  

It is guaranteed that:  

1. The letters are actually in Microsoft Yahei font.  

2. Each letter consists of at least 20 pixels.  

3. Different letters are at least 2 pixels away from each other.

输出

Two integers, the number of 'M' letters and the number of 'S' letters.

样例输入

50 50
..................................................
..................................................
..........................................#.......
............................###..........##.......
.......##..................##.##........#.........
.......##..................#...........##.........
......###.......#..........#...........##.........
......####.....###.........###..........######....
......#.##.....###..........####..............#...
......#.##....####............##..............#...
.....##..#...##.#..........#...#.............##...
.....##..#..##.##..........#####...........##.....
.....#...#.##..##.................................
.....#...###...#..................................
.....#...###...#..................................
.........##...##......................##..........
..............##.....##..............###..........
....................###............###............
...................###.............##.............
..................###.............##..............
.................###..............##..............
................###......###.......########.......
...............###.....#####........########......
..............###...########...............##.....
.............###..#####..##................##.....
............########....###................##.....
...........#######......##.....##.........###.....
............###.........##....###.......####......
.......................###...###.......###........
.......#...............##...###...................
.....####.............###..###....................
...######.............##..###.....................
..####................######......................
..###................######.......................
.###.................#####.......##...............
.###................#####........######...........
.###.................###.........##########.......
..##########.......................##...####......
..############......................##............
....###########......................###..........
.............##.......................###.........
.............###.......................###........
.............###...................#######........
.............##................########...........
............###................####...............
..........####..................######............
.......######......................######.........
.......###.............................##.........
..................................................
..................................................

样例输出

3 4

看到题目都很懵

大神思路:http://hihocoder.com/discuss/question/5288

本题是微软某场笔试的最后一题。由于能做出前3题基本就稳进面试,所以最后一题故意放了一道比较开放的题目,没有什么一定的标准算法。

基本的思路当然是分析M和S哪些统计量会相差比较大,从而足以当作区分的标准。

不过考虑到笔试时间有限,还需要衡量一下写代码的时间,太复杂的方法可能来不及写完代码。

标程使用的方法是,对于每个字母找到笔画的起点和终点。(即下图红圈圈中的像素点,只要起点和终点不偏离圈太远就可以。)

之后考虑连接起点和终点的连线。对于M来说,绝大多数像素点都在连线的同一侧;而对S来说,连线两侧的像素点数量大致相等。

找起点和终点可以用2遍BFS的方法:从字母中随便选取一点P,找距离P最远的点A,再找距离A最远的点B。将A和B当作起点和终点。

判断在连线哪一侧,是一个基本的计算几何问题,可以用向量叉积判断。

import java.util.*;
import static java.lang.Math.sqrt;

public class Main {
    private static int h, w, min_x, max_x, min_y, max_y;
    private static boolean visited[][] = new boolean[501][501];
    private static String image[] = new String[501];

    public static void main(String[] args) {
        int m = 0, s = 0;
        for (int i = 0; i < 501; i++) {
            for (int j = 0; j < 501; j++) {
                visited[i][j] = false;
            }
        }
        Scanner sc = new Scanner(System.in);
        String ss = sc.nextLine();
        String[] tm = ss.split(" ");
        h = Integer.parseInt(tm[0]);
        w = Integer.parseInt(tm[1]);
        for (int i = 0; i < h; i++)
            image[i] = sc.nextLine();
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (image[i].charAt(j) == '.' || visited[i][j])
                    continue;
                min_x = i;
                min_y = j;
                max_x = i;
                max_y = j;
                point node = new point(i, j);
                point p1 = dfs(node);
                point p2 = dfs(p1);
                point middle = new point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
                point center = new point((min_x + max_x) / 2, (min_y + max_y) / 2);
                double dist1 = dist(p1, p2);
                double dist2 = dist(middle, center);
                if (dist2 / dist1 < 0.4)
                    s++;
                else
                    m++;
            }
        }
        System.out.println(Integer.toString(m)+" "+Integer.toString(s));
    }

    static point dfs(point head) {
        int[][] move = {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};
        int[] st = new int[2];
        Queue<point> q = new LinkedList<point>();
        Set<String> s = new HashSet<String>();
        q.offer(head);
        s.add(head.FormatString());
        visited[head.x][head.y] = true;
        point tmp = null;
        while (!q.isEmpty()) {
            tmp = q.poll();
            for (int i = 0; i < 8; i++) {
                int x = tmp.x + move[i][0];
                int y = tmp.y + move[i][1];
                point node = new point(x, y);
                if (x >= 0 && x < h && y >= 0 && y < w && image[x].charAt(y) == '#' && false == s.contains(node.FormatString())) {
                    q.offer(node);
                    s.add(node.FormatString());
                    visited[x][y] = true;
                    min_x = x < min_x ? x : min_x;
                    max_x = x > max_x ? x : max_x;
                    min_y = y < min_y ? y : min_y;
                    max_y = y > max_y ? y : max_y;
                }
            }
        }
        return tmp;
    }

    static double dist(point p1, point p2) {
        return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
    }
}

class point {
    int x;
    int y;

    point(int a, int b) {
        x = a;
        y = b;
    }

    String FormatString(){
        return String.format("%s-%s",Integer.toString(this.x),Integer.toString(this.y));
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_38970751/article/details/85843143
ms