Вот решение, использующее MiniZin c (извините за то, что не предоставил решение Python):
include "globals.mzn";
int: N = 4;
set of int: POS = 1..N;
set of int: SEEN = 1..N;
set of int: HEIGHT = 1..N;
array[POS] of SEEN: top = [2, 1, 2, 2];
array[POS] of SEEN: bottom = [2, 4, 3, 1];
array[POS] of SEEN: left = [2, 3, 1, 2];
array[POS] of SEEN: right = [2, 2, 3, 1];
array[POS, POS] of var HEIGHT: height;
constraint forall(p in POS)
(all_different(row(height, p)) /\
all_different(col(height, p)));
predicate sum_seen(array[POS] of var HEIGHT: values, int: seen) =
(sum(i in 2..N)(values[i] > max([values[j] | j in 1..i-1])) = seen - 1);
constraint forall(p in POS)
(sum_seen(row(height, p), left[p]) /\
sum_seen(reverse(row(height, p)), right[p]) /\
sum_seen(col(height, p), top[p]) /\
sum_seen(reverse(col(height, p)), bottom[p]));
solve satisfy;
output ["height = "] ++ [show2d(height)];
Ключевое наблюдение заключается в том, что для каждой строки количество раз, превышающее максимальное здание высота в строке увеличивается, равняется количеству зданий, которые видны в этой строке (заданные значения). Соответствующие удержания для столбцов и обратные для строк и столбцов.