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.


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

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


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


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''')

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


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)

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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.