Заполните озера, 2D


22

Одномерный вариант этой задачи было довольно легко, так что здесь сложнее 2D версия.

На стандартном входе вам дается двумерный массив высот земли, и вы должны выяснить, где образуются озера, когда идет дождь. Карта высот представляет собой просто прямоугольный массив чисел 0-9 включительно.

8888888888
5664303498
6485322898
5675373666
7875555787

Вы должны вывести тот же массив, заменив все места, которые были бы под водой *.

8888888888
566*****98
6*85***898
5675*7*666
7875555787

Вода может вытекать по диагонали, поэтому в этой конфигурации не будет озера.

888
838
388

самый короткий код выигрывает. Ваш код должен обрабатывать размеры до 80 в ширину и 24 в высоту.

Еще три примера:

77777    77777
75657    7*6*7
75757 => 7*7*7
77677    77677
77477    77477

599999    599999
933339    9****9
936639 => 9*66*9
935539    9*55*9
932109    9****9
999999    999999

88888888    88888888
84482288    8**8**88
84452233 => 8**5**33
84482288    8**8**88
88888888    88888888

4
Было бы неплохо, если возможно, еще несколько тестовых случаев (особенно входные данные, которые вы бы рассмотрели в крайнем случае).
Вентеро

Разрешены ли конечные пробелы в выходных строках?
hallvabo

@hallvabo: нет. Почему ты хочешь?
Кит Рэндалл

Кит: У меня было другое решение, где я добавил строки ввода к фиксированной ширине и сохранил несколько байтов в алгоритме. Если мне нужно удалить отступ для вывода, этот подход занимает больше байтов, чем мое лучшее на данный момент решение.
hallvabo

Ответы:


7

Haskell, 258 символов

a§b|a<b='*'|1<3=a
z=[-1..1]
l m=zipWith(§)m$(iterate(b.q)$b(\_ _->'9'))!!(w*h)where
 w=length m`div`h
 h=length$lines m
 q d i=max$minimum[d!!(i+x+w*y)|x<-z,y<-z]
 b f=zipWith(\n->n`divMod`w¶f n)[0..]m
 (j,i)¶g|0<i&&i<w-2&&0<j&&j<h-1=g|1<3=id
main=interact l

Пример выполнения:

$> runhaskell 2638-Lakes2D.hs <<TEST
> 8888888888
> 5664303498
> 6485322898
> 5675373666
> 7875555787
> TEST
8888888888
566*****98
6*85***898
5675*7*666
7875555787

Проходит все юнит-тесты. Нет произвольных ограничений по размеру.


  • Редактировать (281 → 258): не проверять на стабильность, просто переходить к верхней границе; прекратить передавать постоянный аргументm

5

Python, 483 491 символов

a=dict()
def s(n,x,y,R):
 R.add((x,y))
 r=range(-1,2)
 m=set([(x+i,y+j)for i in r for j in r if(i,j)!=(0,0)and(x+i,y+j)not in R])
 z=m-set(a.keys())
 if len(z)>0:return 1
 else:return sum(s(n,k[0],k[1],R)for k in[d for d in m-z if a[(d[0],d[1])]<=n])
i=[list(x)for x in input().strip().split('\n')]
h=len(i)
w=len(i[0])
e=range(0,w)
j=range(0,h)
for c in[(x,y)for x in e for y in j]:a[c]=int(i[c[1]][c[0]])
for y in j:print(''.join([('*',str(a[(x,y)]))[s(a[(x,y)],x,y,set())>0] for x in e]))

Я уверен, что есть лучший (и более короткий) способ сделать это


В основном работает, но я должен заменить input()с sys.stdin.read()и удалите завершающую \nиз моих образцов входов.
Кит Рэндалл

@ Кейт Рэндалл - sys.stdin.read()читает из файла, верно? Я все еще довольно новичок в Python.
Система отключена

sys.stdin.read()читает STanDard INput до EOF. input()читает и оценивает одну строку стандартного ввода.
Кейт Рэндалл

4

Python, 478 471 символов

(Не включая комментарии. 452 450 символов без учета импорта.)

import sys,itertools
i=[list(x)for x in sys.stdin.read().strip().split('\n')]
h=len(i)
w=len(i[0])
n=h*w
b=n+1
e=range(h)
d=range(w)
# j is, at first, the adjancency matrix of the graph.
# The last vertex in j is the "drain" vertex.
j=[[[b,1][(t-r)**2+(v-c)**2<=1 and i[r][c]>=i[t][v]] for t in e for v in d]+[[b,1][max([r==0,r>h-2,c==0,c>w-2])]]for r in e for c in d]+[[0]*b]
r=range(b)
for k,l,m in itertools.product(r,repeat=3):
    # This is the Floyd-Warshall algorithm
    if j[l][k]+j[k][m]<j[l][m]:
        j[l][m]=j[l][k]+j[k][m]
# j is now the distance matrix for the graph.
for k in r:
    if j[k][-1]>n:
        # This means that vertex k is not connected to the "drain" vertex, and is therefore flooded.
        i[k/w][k-w*(k/w)]='*'
for r in e:print(''.join(i[r]))

Идея в том, что я строю ориентированный граф, в котором каждая ячейка сетки имеет свою собственную вершину (плюс одну дополнительную «сливную» вершину). В графе есть ребро от каждой ячейки с более высокими значениями до соседних ячеек с более низкими значениями, плюс есть ребро от всех внешних ячеек до «сливной» вершины. Затем я использую Floyd-Warshall, чтобы вычислить, какие вершины связаны с «сливной» вершиной; любые не связанные вершины будут затоплены и обозначены звездочкой.

У меня нет большого опыта в сжатии кода Python, поэтому, возможно, есть более лаконичный способ, которым я мог бы реализовать этот метод.


3

Common Lisp, 833

(defun drains (terr dm a b)
  (cond
    ((= (aref dm a b) 1) t)
    ((= (aref dm a b) -1) nil)
    ((or (= a 0) (= b 0)
     (= a (1- (array-dimension terr 0)))
     (= b (1- (array-dimension terr 1)))) t)
    (t (loop for x from -1 to 1
       do (loop for y from 0 to 1
           do (if (and (or (> x 0) (> y 0))
                   (drains terr dm (+ a x) (+ b y))
                   (<= (aref terr (+ a x) (+ b y))
                   (aref terr a b)))
              (progn
                (setf (aref dm a b) 1)
                (return-from drains t)))))
    (setf (aref dm a b) -1)
    nil)))

(defun doit (terr)
  (let ((dm (make-array (array-dimensions terr))))
    (loop for x from 0 to (- (array-dimension terr 0) 1)
       do (loop for y from 0 to (- (array-dimension terr 1) 1)
         do (format t "~a"
            (if (drains terr dm x y)
                (aref terr x y)
                "*"))
         finally (format t "~%")))))

Никаких попыток сделать это не было, я просто нашел проблему интересной. Ввод - это двумерный массив карты. Решение проверяет каждый квадрат, чтобы увидеть, «сливается» ли он - квадрат сливается, если он находится на внешнем крае, или если он находится рядом с квадратом равной или меньшей высоты, который сливается. Чтобы избежать повторения бесконечно, в коде хранится «карта стока» (dm), в которой хранится состояние дренажа уже определенных квадратов.


Ваша описанная логика не совсем верна, так как она неправильно обрабатывает случай с островом.
Кит Рэндалл

1

Питон, 246 символов

import os
a=list(os.read(0,2e3))
w=a.index('\n')+1
a+=' '*w
def f(p,t):
    if e<a[p]or p in t:return
    t[p]=1
    return'*'>a[p]or any(f(p+d,t)for d in(~w,-w,-w+1,-1,1,w-1,w,w+1))
z=0
for e in a:
    if(' '<e)*~-f(z,{}):a[z]='*'
    z+=1
print''.join(a[:~w])

Решение работает путем создания DFS из каждой позиции, чтобы определить, заполнять или нет.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.