Подсчет подматрицы со всеми простыми числами - PullRequest
0 голосов
/ 25 апреля 2018

Мне дана матрица NxN. Подматрица считается особой, если она удовлетворяет следующему условию:

  1. Это должен быть квадрат в форме
  2. Все числа должны быть простыми.

Мне нужно подсчитать общее количество подматриц данной матрицы, которое удовлетворяет следующим критериям.

Например, пусть пример ввода будет =>

3
3 5 6
8 3 2
3 5 2

Пример вывода: 8

Пояснение:

  • 1x1: есть 7 простых чисел, и каждая матрица 1x1 содержит 1 простое число
  • 2x2: только нижняя правая подматрица содержит все простые числа
  • 3x3: матрица 3x3 не удовлетворяет этим критериям

Итак, окончательный ответ (7 + 1 + 0) = 8

Я недавно столкнулся с этим вопросом в интервью. И я мог бы предложить решение грубой силы. Как лучше всего решить этот вопрос?

[ОБНОВЛЕНО] Я вставил свою попытку решить проблему.

class TestClass 
{
    public static boolean isPrime(int n)
    {
        if(n<2)
            return false;
        for(int i=2;i<=Math.sqrt(n);i++)
        {
            if(n%i==0)
                return false;
        }
        return true;
    }
    public static boolean scan_matrix(boolean a[][], int start_i, int start_j, int n)
    {
        for(int i=start_i;i<start_i+n;i++)
        {
            for(int j=start_j;j<start_j+n;j++)
            {
                if(!a[i][j])
                    return false;
            }
        }
        return true;
    }
    public static int count_valid_matrix(boolean a[][], int n, int N)
    {
        int result = 0;
        for(int start_i=0;start_i<=N-n;start_i++)
        {
            for(int start_j=0;start_j<=N-n;start_j++)
            {
                if(scan_matrix(a, start_i, start_j, n))
                    result += 1;
            }
        }
        return result;
    }

    public static void main(String args[]) throws Exception
    {
        Scanner s = new Scanner(System.in);
        int N = s.nextInt();
        boolean a[][] = new boolean[N][N];
        int result = 0;
        for(int i=0;i<N; i++)
        {
            for(int j=0;j<N;j++)
            {
                int num = s.nextInt();
                a[i][j] = isPrime(num);
                if(a[i][j])
                    result += 1;
            }
        }
        int n = 2;
        while(n<N)
        {
            result += count_valid_matrix(a, n, N);
            n++;
        }
        System.out.println(result);
    }
}

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Идея

Сначала преобразуйте (а вы сделали) свою матрицу в матрицу 0/1, с 0 для не простых чисел и 1 для простых чисел.

Теперь у вас есть "поверхность" 1 с. Сколько квадратов вы можете поставить на этой поверхности? Подумайте об этом: если у вас есть 3*3 квадрат 1 с, начинающийся с (0,0), то вы уже Знайте, что квадраты (1,0)-(2,1), (0,1)-(1,2) и (1,1)-(2,2) состоят из 1 с, поэтому вам не нужно проверять эти квадраты снова. Следовательно, вы будете искать квадраты 1 с, начиная с (1,0), (0,1) или (1,1), , только если они больше 2*2. Представьте, что самый большой квадрат, начинающийся с (1,0), имеет размер 3*3, а два других - 2*2. Вы можете игнорировать последнее (они не добавляют ничего нового), но вы должны добавить новый квадрат 3*3 и удалить перекрывающуюся поверхность с предыдущим.

Это можно обобщить следующим образом:

  • хранить самый большой размер квадрата, начиная с (0,0), в матрице M
  • let N = количество квадратов в квадрате размером M[0,0]
  • для каждого (r,c), слева направо и сверху вниз:
    • получить от M наибольшего размера квадрата, начиная с (r-1,c), (r,c-1) или (r-1,c-1), скажем, K
      • вычисляет наибольший размер квадрата, начиная с (r,c) (начиная с K-1)
      • если M[r,c] = K-1, ничего не делать
      • , если M[r,c]> K-1, обновить N: N + = количество квадратов в квадрате размером M[r,c] - количество квадраты в квадрате размером K-1

Хитрость в том, что «вычисление наибольшего размера квадрата, начинающегося с (r,c) (начиная с K-1)» избавит от многочисленных сравнений.

Псевдокод (как Python)

Во-первых, обратите внимание, что квадрат размером k содержит k^2 квадратов размером 1, (k-1)^2 квадратов размер 2, ..., 1 квадрат размера k. Это хорошо известная сумма (я взял результат из Википедии!):

subsquares_count(k) = 1/6*k + 1/2*k^2 + 1/3*k^3

Рассчитать размер самого большого квадрата из 1 s, начиная с (r, c), несложно. Я добавляю начало с K:

def largest_square_size(m, r, c, K):
    k = K
    while k<n:
        # check the border
        for l in 0..k:
            if m[r+k, c+l] == 0 or m[r+l, c+k] == 0: # consider the left and bottom borders
                break while
        if m[r+k, c+k] == 0 # don't forget the corner
            break while
        k += 1
    return k

Теперь эскиз основного цикла:

for r in 0..n:
    for c in 0..n: 
        K = max(M[r-1,c-1], M[r-1,c], M[r,c-1]) - 1 # add boundary check, K = 0 if r,c = 0,0
        M[r,c] = largest_square_size(m, r, c, K)
        if M[r,c] > K:
            N += subsquares_count(M[0,0]) - subsquares_count(K)

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я не проверял это, и, возможно, есть крайние случаи, но я думаю, что это правильно.

Это явно неоптимальный вариант, поскольку некоторые позиции можно проверять более одного раза, но они должны работать хорошо.

0 голосов
/ 25 апреля 2018

Вот часть одной возможной формулировки.Пусть is_special(I, J, W) представляет, является ли ячейка матрицы m(I, J) нижним правым углом действительного квадрата ширины W.Тогда:

is_special(I, J, 1) ->
  is_prime( m(I, J) );

is_special(I, J, W) ->
  (I >= W - 1 andalso                     % assuming I starts from 0
    (J >= W - 1 andalso                   % assuming J starts from 0
      (is_special(I, J, W - 1) and
       is_special(I - 1, J, W - 1) and
       is_special(I, J - 1, W - 1) and
       is_special(I - 1, J - 1, W - 1)))).
...