Заповнення озер, 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

Пітон, 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з моїх зразків входів.
Кіт Рендалл

@Keith Randall - sys.stdin.read()читає з файлу правильно? Я все ще досить новий в Python.
Система вниз

sys.stdin.read()читає вхід STanDard до EOF. input()читає та оцінює один рядок стандартного введення.
Кіт Рендалл

4

Пітон, 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

Загальний Лісп, 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.