Encontre um criminoso no ouvido, dedo e cabeça

17

Antes da descoberta de impressões digitais e testes de DNA, a polícia britânica usou um sistema antropométrico para identificar reincidentes. Certas partes dos corpos dos criminosos foram medidas e armazenadas em registros - presume-se que essas partes do corpo não mudem de tamanho após a idade adulta. Este sistema era conhecido como bertillonnage .

O diagrama abaixo mostra um sistema de arquivamento usado pela polícia para acessar esses registros rapidamente.

Mesa Diagrama 1: Um sistema de arquivamento com gavetas numeradas.
Nota: se você não conseguir ver a imagem, tente o espelho imgur ou compile você mesmo .

O armário de arquivos é composto por 81 gavetas numeradas. Cada gaveta contém cartões e cada cartão tem medidas de partes específicas do corpo de um criminoso:

  • O comprimento da cabeça ( H)
  • A largura de suas cabeças ( B)
  • A largura da orelha direita ( E)
  • O comprimento do dedo indicador ( F)

Cada medida é classificada como pequena, média ou grande.

Por exemplo, a gaveta 56 contém placas com as seguintes características: H pequeno, grande B, meio E, e pequena F. Isto pode ser simbolizada usando as letras S, Me Lem lugar de pequeno, médio e grande:

SH,LB,ME,SF

Observe que a letra do tamanho vai primeiro, depois qual é a medida. Além disso, um ponto de exclamação !pode ser colocado na frente para causar um resultado negativo:

!SH,LB,!ME,SF

Isso indica cartões com as seguintes características: não pequeno H, grande B, não médio E e pequeno F. Existem quatro gavetas que contêm cartões com essas características - 58, 60, 61 e 63.

Sua tarefa é escrever um programa que, ao receber uma sequência notando algumas características, produza todas as gavetas que contêm cartões com essas características. Se não houver gavetas que contenham cartões com as características especificadas, produza 0.

Aqui estão algumas entradas e saídas de amostra.

  1. Entrada: SH,LB,ME,SF
    Saída:56
  2. Entrada: !SH,LB,!ME,SF
    Saída:58,60,61,63
  3. Entrada: SB,!MF,!LF
    Saída:1,2,3,4,5,6,7,8,9
  4. Entrada: MH,!MH
    Saída:0

Isso é código de golfe, portanto a entrada mais curta vence. Faça perguntas nos comentários se a especificação não estiver clara.

absinto
fonte
Como uma nota histórica de precisão, os sistemas de bertillonnage eram realmente muito mais complicados do que esta versão simplificada, usando 9 medições em vez de 4 e, portanto, usando um sistema de arquivamento mais envolvido do que o descrito aqui.
absinto
4
Ah não! NÃO OUTRA pergunta do Sudoku ;-)
Level River St
11
@steveverrill eu realmente fiz o diagrama de um modelo sudoku, por isso há alguma verdade nisso: o
o absinto

Respostas:

1

GolfScript 95 ( DEMO )

','/:r;81,{r{1$[[.9%3/\.3%\.27/\9/3%]{'SML'=}%'HEBF']zip{''+}%\.,3=\1${(;}*@?)!!=},!\;},{)}%0or
Cristian Lupascu
fonte
6

Ruby 1.9.3 - 173 157 143

x=(1..81).select{|j|$*[0].split(?,).all?{|y|i=j-1
z='SML'
[z[i%9/3]+?H,z[i%3]+?E,z[i/27]+?B,z[i/9%3]+?F].member?(y[-2,2])^y[?!]}}
p x==[]?[0]:x

Editar:

  • aplicou as dicas do Three If By Whiskey .
  • parâmetros da linha de comando para salvar mais alguns caracteres

Demonstração on-line: http://ideone.com/lodTLt

Cristian Lupascu
fonte
selecté um sinônimo mais curto para find_all. Você pode aparar outros dois caracteres substituindo y[-2..-1]por y[-2,2]e mais três usando, em ==[]vez de .empty?.
Three If Por Whisky
@ThreeIfByWhiskey Ótimas dicas, obrigado! Eu editei minha resposta.
Cristian Lupascu
2

Scala - 951

Definitivamente não ganhará este, principalmente devido aos nomes das funções incorporadas, eu acho.

def m(a: List[Int]) = 0 to 8 flatMap (x => a map (_ + 9*x)) toSet
var SH = m(List(1,2,3))
var MH = m(List(4,5,6))
var LH = m(List(7,8,9))
var SE = m(List(1,4,7))
var ME = m(List(2,5,8))
var LE = m(List(3,6,9))
var SB = 1 to 27 toSet
var MB = 28 to 54 toSet
var LB = 55 to 81 toSet
def l(a: List[Int]) = 0 to 2 flatMap (x => a map (_+27*x)) toSet
var SF = l(1 to 9 toList)
var MF = l(10 to 18 toList)
var LF = l(19 to 27 toList)

var j = Map(("LH",LH),("MH",MH),("SH",SH),("LB",LB),("MB",MB),("SB",SB),("LF",LF),("MF",MF),("SF",SF),("LE",LE),("ME",ME),("SE",SE))

def f(x : String) = {
  def h(i : List[String], k : Set[Int]) : Set[Int] = {
      if(i isEmpty) k
      else if(i.head.startsWith("!")) h(i.tail, k filterNot (j(i.head.replace("!","")) contains _))
      else h(i.tail, k intersect j(i.head))
  }
  h(x split "," toList, 1 to 81 toSet) mkString ","
}

O argumento é passado para a função f

f("SH,LB,ME,SF") = 56

Bakerg
fonte
2

T-SQL - 547 544

Não é uma entrada vencedora, mas é adequada para esse tipo de problema.

Configuração da tabela de grade - 254

SELECT ROW_NUMBER()OVER(ORDER BY (SELECT $))I,LEFT(Z,1)E,RIGHT(Z,1)H,LEFT(Y,1)F,RIGHT(Y,1)B INTO G FROM(VALUES('SS'),('MS'),('LS'),('SM'),('MM'),('LM'),('SL'),('ML'),('LL'))FB(Y),(VALUES('SS'),('MS'),('LS'),('SM'),('MM'),('LM'),('SL'),('ML'),('LL'))EH(Z)

Consulta - 293 290

DECLARE @S CHAR(400)='SELECT ISNULL(SUBSTRING(O,2,99),0)FROM (SELECT CONCAT('','',I)FROM G WHERE '+REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REVERSE(@i),',',' AND '),'S!','!S'),'M!','!M'),'L!','!L'),'S','=''S'''),'M','=''M'''),'L','=''L''')+' FOR XML PATH(''''))O(O)';EXEC(@S)

A entrada é feita declarando @i antes da consulta

DECLARE @I VARCHAR(50) = 'SB,!MF,!LF';

Eu poderia salvar mais 89 caracteres se a saída não precisar ser delimitada por vírgula

DECLARE @S CHAR(400)='SELECT I FROM G WHERE '+REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REVERSE(@i),',',' AND '),'S!','!S'),'M!','!M'),'L!','!L'),'S','=''S'''),'M','=''M'''),'L','=''L''')
MickyT
fonte
1

Mathematica 191 235

Representa cada número de célula na base 3. Cada posição de dígito representa um recurso físico. O valor do dígito {0,1,2} representa "Pequeno", "Médio", "Grande", respectivamente.

Os recursos correspondem aos dígitos da seguinte maneira:

{"widthOfHead", "IndexFingerLength", "LengthOfHead", "WidthOfRightEar"}

Por exemplo, a entrada,

{"SH","LB","ME","SF"}

significa:

"LB" implica em larguraOfHead = 2 (grande)

"SF" implica IndexFingerLength = 0 (pequeno)

"SH" implica LengthOfHead = 0 (pequeno)

"ME" implica WidthOfRightEar = 1 (médio)

2001na base 3 é 55 na base 10.

Precisamos adicionar um porque estamos contando células de 1, não zero.


Código

c=Characters;t=Table[IntegerDigits[k,3,4],{k,0,80}];
f@i_:=1+FromDigits[#,3]&/@Intersection@@(Cases[t,#]&/@(ReplacePart[{_,_,_,_},{#}]&/@(c/@i
/.Thread[c@"BFHESML"-> {1,2,3,4,0,1,2}]/.{{"!",v_,n_}:> (n-> Except[v]),{v_Integer,n_}:> n-> v})))
/.{}:>0

Casos de teste

f[{"SH","LB","ME","SF"}]

{56}


f[{"!SH","LB","!ME","SF"}]

{58, 60, 61, 63}


f[{"SB","!MF","!LF"}]

{1, 2, 3, 4, 5, 6, 7, 8, 9}


f[{"MH","!MH"}]

0 0

DavidC
fonte
1

Python 3-192 - Experimente!

from itertools import*
S=input().split(',')
print([i+1for i in range(81)if eval('*'.join('(list(product(*["SML"]*4))[i][%d]%s="%s")'%('BFHE'.find(s[-1]),'!='[s[0]>'!'],s[-2])for s in S))]or 0)
Falko
fonte
1

Python 2-194

from itertools import*
n=map(set,['012']*4)
for x in raw_input().split(','):n['BFHE'.find(x[-1])]&=set(`'SML'.find(x[-2])`)^set('012'*(x<'"'))
print[1+int(''.join(x),3)for x in product(*n)]or[0]

A saída tem colchetes e não se preocupa com a ordem da saída.
Algumas sugestões da Falko e algumas de mim para tirar 10 caracteres.

Bizangles
fonte
Sim, não há problema em colocar a entrada entre colchetes.
absinto
Eles precisam estar em ordem?
Bizangles
Boa pergunta. Na verdade, a saída não tem que estar em ordem - embora eu não tenho certeza de como reproduzi-los em uma ordem diferente iria salvar caracteres.
o absinto
Estou usando python set () s, convertendo-os novamente em listas, obtendo o produto, convertendo em números de base 3 em ints. Em tudo isso, a ordem fica um pouco confusa e eu preciso usar o sortido () se quiser que eles voltem na ordem certa.
Bizangles
Entendo. O pedido não é importante, portanto, os classificados () podem ser removidos. Ótima solução.
absinto