Расшифровать тепловую карту


32

Схемы Зоны активности

Рассмотрим прямоугольную комнату, на потолке которой у нас есть тепловизионная камера, направленная вниз. В комнате есть несколько источников тепла интенсивности 1-9, фоновая температура 0. Тепло рассеивается от каждого источника, падая на одну единицу за (недиагональный) шаг. Например, 20x10комната

...........1........
....................
...8................
..5...............2.
....................
.1..................
................1...
.................65.
....................
............2.......

содержит 9 источников тепла, и температурный градиент, показанный тепловой камерой

34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432

В графической форме это может выглядеть так:

тепловая карта 9 источников

Из градиента мы можем определить положение и интенсивность некоторых источников тепла, но не всех. Например, все 9s всегда могут быть выведены, так как они имеют максимальную температуру, как и 8в этом случае, так как это создает локальный максимум в градиенте. 2Вблизи правая граница также может быть выведено, даже если он не находится на локальном максимуме, так как он не имеет другого , 2как соседа. В 5s, с другой стороны, не выводится, так как их тепло может также быть получены путем более интенсивных источников вблизи них. В 0s известен не содержит никаких источников тепла, но и все остальные плитки могут потенциально содержать один. Давайте обозначим неопределенные плитки дефисами-, определенные источники тепла по соответствующим цифрам и определенное пустое пространство по периодам .:

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

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

правила

Вам предоставляется ввод в виде строки, разделенной либо новыми строками, либо вертикальными трубами |, в зависимости от того, что удобнее, и выходные данные должны иметь ту же форму. На входе и / или выходе может быть конечный разделитель, но не предшествующий. Размер ввода может варьироваться, но его ширина и высота всегда как минимум 4. Обе функции и полные программы являются приемлемыми. Побеждает меньшее количество байтов, и стандартные лазейки запрещены.

Дополнительные тестовые случаи

Входные данные:

898778765432100
787667654321100
677656543211210
678765432112321
567654321123210

который выглядит так в графической форме:

контрольный пример 1

Выход:

-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.

Входные данные:

7898
8787
7676
6565

Выход:

--9-
8---
----
----

Входные данные:

00001
00000
00000
10000

Выход:

....1
.....
.....
1....

1
Вы не возражаете, если я добавлю 2 графики тепловых карт к вашему вопросу, если вы думаете, что они добавляют ценность? Это всего лишь 2-минутный эксперимент.
Рыцарь логики

@CarpetPython Конечно, продолжай. Они выглядят очень мило для меня. Вы также можете добавить «Courtesy of CarpetPython», чтобы получить кредит. ;)
Згарб

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

Почему бы не разрешить ввод в виде двумерного массива вместо строки?
feersum

@feersum, как правило, методы ввода являются последовательными.
Оптимизатор

Ответы:


10

CJam, 73 69 62 55 байтов

ОБНОВЛЕНИЕ : Новый алгоритм. Короче и больше возможностей для улучшения

qN/5ff*{{[{_@_@<{I'0t}*\}*]W%}%z}4fI{):X-'-X~X'.??}f%N*

Как это работает

Логика похожа на алгоритм ниже, но здесь я не проверяю всех 4 соседей за одну итерацию. Вместо этого я использую меньший подход, чтобы перебрать все строки и столбцы в обоих направлениях. Вот эти шаги:

  • Преобразуйте каждый символ в наборы по 5. Первые 4 будут изменены, чтобы сказать, если они больше, чем соседняя ячейка в строке во время итерации. Последний для сравнения.
  • Итерируйте по каждой строке и уменьшайте по каждой строке. При сокращении у меня есть две 5-символьные строки. Я знаю, какая итерация [0 для нормальных строк, 1 перевернутых столбцов, 2 для перевернутых строк и 3 для нормальных столбцов] Я обновляю i- й символ в первой строке из 5 символов и делаю его 0, если он меньше второго ,
  • После всех 4 итераций, если все 5 символов одинаковы и не равны нулю, то это локальные максимумы. Я сопоставляю все строки из 5 символов и преобразую их либо в одну цифру, .либо -.

Вот пример запуска на небольшом входе:

7898
8787
7676
6565

После первого шага:

["77777" "88888" "99999" "88888"
 "88888" "77777" "88888" "77777"
 "77777" "66666" "77777" "66666"
 "66666" "55555" "66666" "55555"]

После второго шага:

["00777" "08888" "99999" "88088"
 "88888" "07007" "88808" "77007"
 "77707" "06006" "77707" "66006"
 "66606" "05005" "66606" "55005"]

После последнего сопоставления с одним символом, окончательный вывод:

--9-
8---
----
----

Объяснение кода :

qN/5ff*                         "Split the input on new line and convert each character";
                                "to string of 5 of those characters.";
{{[{             }*]W%}%z}4fI   "This code block runs 4 times. In each iteration, it";
                                "maps over each row/column and then for each of them,";
                                "It reduce over all elements of the row/column";
                                "Using combination of W% and z ensures that both rows and";
                                "columns are covered and in both directions while reducing";
    _@_@                        "Take a copy of last two elements while reducing over";
        <                       "If the last element is bigger than second last:";
         {I'0t}*\               "Convert the Ith character of the 5 char string of"
                                "second last element to 0";
                                "We don't have to compare Ith character of last two 5 char";
                                "string as the smaller one will be having more leading";
                                "0 anyways. This saves 4 bytes while comparing elements";
{):X-'-X~X'.??}f%N*             "This part of code converts the 5 char back to single char";
 ):X                            "Remove the last character and store in X. This last char";
                                "was not touched in the prev. loop, so is the original char";
    -                           "Subtract X from remaining 4 char. If string is not empty";
                                "then it means that it was not all same characters";
                                "In other words, this character was smaller then neighbors";
     '-      ?                  "If non-empty, then replace with - else ...";
       X~X'.?                   "if int(X) is zero, put . else put X";
               f%N*             "The mapping code block was run for each row and then";
                                "The rows are joined by newline.";

Попробуй здесь


Старый подход

qN/~_,):L0s*]0s*:Q_,{QI=:A[W1LL~)]If+Qf=$W=<'-A?A~\'.?I\t}fIL/W<Wf<N*

Как это работает

Логика проста, итерация по сетке и посмотреть, больше или равно текущее значение для остальных четырех соседей - вверх, вниз, влево и вправо. Затем преобразуйте текущее значение на основе приведенного выше правила и, если оно равно 0, сделайте его "." ,

Код Объяснение

qN/~_,):L0s*]0s*:Q         "This part of code pads the grid with 0s";
qN/~                       "Read the input, split on new lines and unwrap the arrays";
    _,):L                  "Copy the last row, taken length, increment and store in L";
         0s*               "Get L length 0 string";
            ]0s*           "Wrap everything in an array and join the rows by 0";
                :Q         "Store this final single string in Q";

_,{        ...      }fI    "Copy Q and take length. For I in 0..length, execute block";
   QI=:A                   "Get the I'th element from Q and store in A";
   [WiLL~)]If+             "This creates indexes of all 4 neighboring cells to the Ith cell";
              Qf=          "Get all 4 values on the above 4 indexes";
                 $W=       "Sort and get the maximum value";
<'-A?                      "If the current value is not the largest, convert it to -";
     A~\'.?                "If current value is 0, convert it to .";
           I\t             "Update the current value back in the string";
{ ... }fIL/                "After the loop, split the resulting string into chunks of L";
           W<Wf<           "Remove last row and last column";
                N*         "Join by new line and auto print";

Попробуйте онлайн здесь


5
Должен сказать, я редко слышу «слишком долго» при описании кода CJam.
Алекс А.

6

JavaScript (ES6) 99

F=h=>[...h].map((c,i)=>[o=~h.search('\n'),-o,1,-1].some(d=>h[d+i]>c)&c>0?'-':c=='0'?'.':c).join('')

Тест в консоли Firefox / FireBug

console.log(F('\
34565432100100000000\n\
45676543210000000000\n\
56787654321000000110\n\
45676543210000001221\n\
34565432100000012321\n\
23454321000000123432\n\
12343210000001234543\n\
01232100000012345654\n\
00121000000011234543\n\
00010000000121123432\n'),'\n\n',
F('\
898778765432100\n\
787667654321100\n\
677656543211210\n\
678765432112321\n\
567654321123210\n'), '\n\n',
F('7898\n8787\n7676\n6565\n'))

Выход

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------


-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.


--9-
8---
----
----

4

Python 2: 154 байта

b=input()
l=b.index('\n')+1
print''.join(('\n.'+('-'+v)[all([v>=b[j]for j in i-l,i-1,i+l,i+1if 0<=j<len(b)])])[('\n0'+v).index(v)]for i,v in enumerate(b))

Ввод должен быть в форме "00001\n00000\n00000\n10000".

Преобразование строки в 2D-матрицу довольно долго в Python. Поэтому я сохраняю оригинальный формат строки. Я перечисляю по входу, iэто индекс, vэто символ (наконец, перечислить сохраненные байты в решении для гольфа!). Для каждой пары (i,v)я вычисляю правильный символ вывода и присоединяюсь к ним. Как выбрать правильный выходной символ? Если v == '\n'выходной символ есть \n, то v == '0'выходной символ есть '.'. В противном случае я проверяю 4 соседа v, которые b[i-b.index('\n')-1](выше), b[i-1](слева, b[i+1](справа) и b[i+b.index('\n')+1](ниже), если они есть, <= vи выбираю символ '-'илиv, Здесь я сравниваю символы, а не числа, но это работает вполне нормально, потому что значения ascii находятся в правильном порядке. Также нет проблем, если b[i-1]или b[i+1]равных '\n', потому что ord('\n') = 10.

Pyth: 61 58

JhxQbVQK@QN~k@++b\.?\-f&&gT0<TlQ<K@QT[tNhN-NJ+NJ)Kx+b\0K)k

Более или менее перевод скрипта Python. Довольно некрасиво ;-)

Попробуйте онлайн: Pyth Compiler / Executor Тот же формат ввода, что и в решении Python.

JhxQb      Q = input()
  xQb      Q.index('\n')
 h         +1
J          store in J

VQK@QN~k.....)k   k is initialized as empty string
VQ           )    for N in [0, 1, 2, ..., len(Q)-1]:
  K@QN                K = Q[n]
      ~k              k += ... (a char, computed in the next paragraph)
             )    end for
              k   print k

@...x+b\0K   ... is a char of len 3 (is constructed below)
     +b\0    the string "\n0"
    x    K   find Q[d] in this string and return index, if not found -1
@...         lookup in string at the computed position (this is done mod 3 automatically!)

++b\.?\-f&&gT0<TlQ<K@QT[tNhN-NJ+NJ)K   not to the string
                       [tNhN-NJ+NJ)    the list [d-1, d+1, d-J, d+j]
        f                              filter the list for indices T which
           gT0                            T >= 0
          &                               and
              <TlQ                        T < len(Q)
         &                                and
                  <K@QT                   Q[d] < Q[T]
     ?\-                           K   use "-" if len(filter) > 0 else Q[d]
                                       this creates the third char
++b\.                                  "\n" + "." + third char

4

Perl, 77, 75, 72 70

Стандартные 2d трюки с регулярным выражением.

#!perl -p0
/
/;$x="(.{@-})?";y/0/./while s/$.$x\K$"|$"(?=$x$.)/-/s||($"=$.++)<9

Пример:

$ perl heat.pl <in.txt
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

Попробуй здесь


3

Ява, 307 , 304 , 303 , 299 298

Это, безусловно, «идеальный» вызов для некоторого Java-программиста :)

class M{public static void main(String[]a){int c=a[0].indexOf('|'),i=c,d,v;char[]r=a[0].replace("|","").toCharArray(),m=new char[(v=r.length+c)+c];for(;i<v;){m[i]=r[i++-c];}for(i=c;i<v;i++){a[0]=i%c<1?"\n":"";d=m[i];System.out.print(a[0]+(d<49?'.':m[i-c]>d|m[i+c]>d|m[i-1]>d|m[i+1]>d?'-':m[i]));}}}

Вход (метод «|»):

34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432

Выход:

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

1
Это может быть 288, если вы удалите пробел в char[]r=a[0].replace("|", <--here"").toCharArray().
bcsb1001

1
Не заметил этого, спасибо! Ну, это делает 298
Рольф ツ

2

APL, 92

('.-',⎕D)[1+(M≠0)+M{(1+⍺)×0≠⍺∧M[J/⍨Z∊⍨J←⍵∘+¨(⌽¨,+)(-,+)⊂0 1]∧.≤⍺}¨Z←⍳⍴M←↑{×⍴⍵:(⊂⍎¨⍵),∇⍞⋄⍬}⍞]

Пример:

       ('.-',⎕D)[1+(M≠0)+M{(1+⍺)×0≠⍺∧M[J/⍨Z∊⍨J←⍵∘+¨(⌽¨,+)(-,+)⊂0 1]∧.≤⍺}¨Z←⍳⍴M←↑{×⍴⍵:(⊂⍎¨⍵),∇⍞⋄⍬}⍞]
34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

Самая длинная программа APL, которую я когда-либо видел. Вы можете заметить, что это не стандартный APL, так как он использует dfns.
FUZxxl

2

Рубин 140

f=->s{
r=s.dup
l=s.index(?\n)+1
(0...s.size).map{|i|
s[i]<?0||r[i]=r[i]<?1??.:[i-1,i+1,i-l,i+l].map{|n|n<0??0:s[n]||?0}.max>r[i]??-:s[i]}
r}

Ничего особенного; просто переберите карту и сравните текущее значение со значением четырех соседей.

Запустите его онлайн с тестами: http://ideone.com/AQkOSY


1

R 223

О лучшем, что я могу придумать на данный момент. Работа со строкой довольно дорогая. Я думаю, что есть возможности для улучшения, но пока не вижу

s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')

Результат испытаний

> s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')
1: 898778765432100|787667654321100|677656543211210|678765432112321|567654321123210
2: 
Read 1 item
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.
> s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')
1: 34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432
2: 
Read 1 item
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
> 

1

J - 69 байт

[:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2

Примеры:

   ([:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2) (0 : 0)
34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432
)
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
   ([:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2) (0 : 0)
898778765432100
787667654321100
677656543211210
678765432112321
567654321123210
)
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.

PS: (0 : 0)это стандартный J способ указания строк. Вы также можете использовать |строки с разделителями (с завершающим |).


1

Excel VBA - 426

Это будет редким случаем, когда VBA выигрывает любые игры в гольф с кодом, но так как это то, чем я больше всего пользуюсь, с этим интересно играть. Первая строка - это крайний случай, который сделал это длиннее, чем должно быть.

Sub m(a)
    b = InStr(a, "|")
    For i = 1 To Len(a)
        t = Mid(a, i, 1)
        Select Case t
            Case "|"
                r = r & "|"
            Case 0
                r = r & "."
            Case Else
                On Error Resume Next
                x = Mid(a, i - 1, 1)
                y = Mid(a, i + 1, 1)
                Z = Mid(a, i + b, 1)
                If i < b Then
                    If t < x Or t < y Or t < Z Then
                        r = r & "-"
                    Else
                        r = r & t
                    End If
                Else
                    If t < x Or t < y Or t < Z Or t < Mid(a, i - b, 1) Then
                        r = r & "-"
                    Else
                        r = r & t
                    End If
                End If
        End Select
    Next
    MsgBox r
End Sub

Количество не включает начальные пробелы.

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

Звонок из непосредственного окна:

m "34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432"

Вывод (в окне):

---------..1........|----------..........|---8-------......--.|----------......--2-|---------......-----|--------......------|-------......-------|.-----......-----6--|..---.......--------|...-.......-2-------

1

Perl - 226

sub f{for(split'
',$_[0]){chomp;push@r,r($_);}for(t(@r)){push@y,r($_)=~s/0/./gr}$,=$/;say t(@y);}sub r{$_[0]=~s/(?<=(.))?(.)(?=(.))?/$1<=$2&&$3<=$2?$2:$2eq'0'?0:"-"/ger;}sub t{@q=();for(@_){for(split//){$q[$i++].=$_;}$i=0;}@q}

Вы можете попробовать это на Ideone . Если кто-то заинтересован в объяснении, дайте мне знать.


Я думаю, у вас есть 226 символов, а не 227.
Кристиан Лупаску

@ w0lf, если вы правы, перевод строки считается за 2, так как я на Windows.
hmatt1

1

Хаскелл - 193

z='0'
r=repeat z
g s=zipWith3(\u t d->zip3(zip(z:t)u)t$zip(tail t++[z])d)(r:s)s$tail s++[r]
f=unlines.map(map(\((l,u),t,(r,d))->case()of _|t==z->'.'|maximum[u,l,t,r,d]==t->t|0<1->'-')).g.lines

fэто функция, которая принимает строку в форме 0001\n0000\n0000\n1000и возвращает требуемую строку.

g это функция, которая принимает список списков символов и возвращает список списков ((влево, вверх), this, (вправо, вниз)).

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