解码热图


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”,以表扬自己。;)
Zgarb 2015年

2
做完了 无需信用,但我认为在编辑之前不提出要求是不礼貌的。
Logic Knight

为什么不允许输入为二维数组而不是字符串?
feersum

@feersum通常输入方法是一致的。
Optimizer

Answers:


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代码时很少听到“太长”的声音。
Alex A.

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"

在Python中,将字符串转换为2D矩阵的过程相当漫长。所以我保留了原始的字符串格式。我枚举输入,i是索引,v是字符(最后枚举高尔夫解决方案中保存的字节!)。对于每对,(i,v)我计算输出的正确字符,然后将它们加入。如何选择正确的输出字符?如果v == '\n'输出char是\n,则v == '0'输出char是'.'。否则,如果,则测试的4个邻居(vb[i-b.index('\n')-1](上方),b[i-1](左,b[i+1](右)和b[i+b.index('\n')+1](在)下方),<= v然后选择char '-'v。在这里,我比较的不是字符,而是数字,但它工作得很好,因为ascii值的顺序正确。也没有任何问题,如果b[i-1]还是b[i+1]等于'\n',因为ord('\n') = 10

积:61 58

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

或多或少是Python脚本的翻译。相当难看;-)

在线尝试:Pyth编译器/执行器与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

Java中,307304303299 298

对于某些Java codegolf来说,这无疑是一个“完美”的挑战:)

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 2015年

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 2015年


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
克里斯蒂安Lupascu

@ w0lf你是对的,因为我在Windows上,所以换行符被计为2。
hmatt1 2015年

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 是一个函数,它接受一个字符列表,并返回一个列表((左,上),此,(右,下))。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.