Estatísticas de pesquisa de engenharia reversa


22

Introdução

Dado um conjunto de porcentagens de opções em uma pesquisa, calcule o número mínimo de eleitores que deve haver na pesquisa para gerar essas estatísticas.

Exemplo: Qual é o seu animal de estimação favorito?

  • Cachorro: 44.4%
  • Gato: 44.4%
  • Rato: 11.1%

Resultado: 9(número mínimo possível de eleitores)

Especificações

Aqui estão os requisitos para o seu programa / função:

  • Você recebe uma matriz de valores percentuais como entrada (em stdin, como argumento de função, etc.)
  • Cada valor percentual é um número arredondado para uma casa decimal (por exemplo, 44.4 44.4 11.1).
  • Calcule o número mínimo possível de votantes na enquete cujos resultados renderiam essas porcentagens exatas quando arredondados para uma casa decimal (em stdout ou valor de retorno da função).
  • Bônus : -15 caracteres, se você puder resolver de uma maneira "não trivial" (ou seja, não envolve a iteração de todos os números possíveis de eleitores até encontrar o primeiro que funcione)

Exemplo

>./pollreverse 44.4 44.4 11.1
9
>./pollreverse 26.7 53.3 20.0
15
>./pollreverse 48.4 13.7 21.6 6.5 9.8
153
>./pollreverse 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 99.6
2000
>./pollreverse 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 98.7
667
>./pollreverse 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 98.7
2000
>./pollreverse 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 97.8
401

Pontuação

Isso é código-golfe, então os personagens mais curtos possíveis vencem. Quaisquer bônus são subtraídos da contagem total de caracteres.


2
Eu acho que isso poderia estar relacionado a mais alguns casos estranhos de teste. 26.7 53.3 20.0(4 8 3 de 15), 48.4 13.7 21.6 6.5 9.8(74 21 33 10 15 de 153) etc.
Gareth

@ Gareth: Bom pensamento. Atualizado com seus casos de teste.
Mellamokb

a soma de todos os votos não deve ser 100%? não está nos últimos quatro casos de teste
Ali1S232 25/04

@ Gajet: Não, nem sempre é igual a 100%. Toda vez que há um arredondamento, você perde até 0.5%o total, e toda vez que há um arredondamento, você soma 0.5%o total. Os últimos quatro casos de teste foram construídos propositadamente para explorar esse fenômeno de maneira otimizada. No primeiro caso de teste que resulta em 2000, cada uma das 9 primeiras entradas representa 1voto (e todas são arredondadas para cima 0.5%), enquanto a última representa 1991votos (e é arredondada para baixo ~ 0.5%). Se você calcular essas porcentagens manualmente e arredondar para uma casa decimal, verá que todas estão corretas.
Mellamokb

Estou lutando com a resposta não trivial no VBA (tentando até agora, não houve nenhuma), mas estou trabalhando nisso!
Gaffi

Respostas:


2

APL (Dyalog Classic) , 48 43 bytes

-5 bytes por Adám

+/0(⊢+{(⌈/⍷⊢)⍺-⍵÷+/⍵})⍣{z≡⍎3⍕⍺÷+/⍺}⍨z←.01×⎕

Programa completo, recebendo informações de stdin.

Experimente online! O link é para a versão dfn.

Ungolfed

normalize   ÷ +/
find_max  {⍵⍷⍨⌈/⍵}
round  {⍎3⍕⍵}
increase  {find_max  - normalize ⍵}
vote_totals  {z←⍺   (⊢+increase)⍣{z  round normalize ⍺} ⍵}
h  {+/ (.01×⍵) vote_totals 0}

Experimente online!

  • normalizedivide ( ÷) todos os elementos do seu argumento correto ( ) pela sua soma ( +/).
  • round(y)arredonda y para 3 casas decimais formatando ( ) e depois avaliando ( ) cada elemento de y.
  • find_max(y) retorna uma matriz com 1 onde max (y) é encontrado e 0 em outro lugar.
  • increase(x,y) usa x (as porcentagens de meta) e y (a matriz dos totais atuais de votos) e calcula onde adicionar 1 em y para aproximar as porcentagens de x.
  • vote_totals(x,y) usa x (as porcentagens de meta) e y (totaliza o voto inicial) e executa f repetidamente, adicionando votos até que as porcentagens sejam arredondadas para x.
    • A sintaxe f ⍣ gsignifica executar frepetidamente até que g(y,f(y))seja verdadeira. Nesse caso, ignoramos f(y).
  • h(x) define y como 0 (equivalente a uma matriz de 0s devido à vetorização), executa g e soma os totais finais de votos.

7

Python, 154

def p(x):
 n=[1]*len(x);d=2;r=lambda z:round(1000.*z/d)/10
 while 1:
    if(map(r,n),sum(n))==(x,d):return d
    d+=1
    for i in range(len(x)):n[i]+=r(n[i])<x[i]

Ele funciona para o último exemplo agora.

Exemplo é executado:

>>> p([44.4, 44.4, 11.1])
9
>>> p([26.7, 53.3, 20.0])
15
>>> p([48.4, 13.7, 21.6, 6.5, 9.8])
153
>>> p([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 99.6])
2000
>>> p([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 98.7])
667
>>> p([0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 98.7])
2000
>>> p([0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 97.8])
401

Eu acho que algo pode estar errado no seu último exemplo; talvez você quis dizer 99.1como o último valor
Cristian Lupascu

2
Eu acho que está certo, mas é bastante confuso. 1/2000 = 0.05%( 0.1%arredondado) e 1991/2000 = 99.55%( 99.6%arredondado). Portanto, se houver dez opções em uma enquete e nove delas forem votadas uma vez, enquanto a última obtiver votos em 1991, isso daria essas porcentagens.
grc

Você está certo. Ótima solução, BTW.
Cristian Lupascu

Eu acho que você pode economizar mais 3 caracteres seguindo esta dica: codegolf.stackexchange.com/a/58/3527 #
Cristian Lupascu

Obrigado, w0lf. Atualizei-o agora para incluir guias. As guias são exibidas como quatro espaços, se alguém estiver se perguntando.
grc

4

J, 57 caracteres

t=:".>'1'8!:0|:100*%/~i.1001
{.I.*/"1(t{~i.#t)e."1~1!:1[1

Usou o método trivial. É preciso entrada do teclado. tcria uma tabela de pesquisa e a segunda linha procura a entrada dentro da tabela. Posso fornecer uma explicação expandida do código, se alguém estiver interessado.

Procurei usar a porcentagem para criar uma fração e, em seguida, obter a forma mais baixa da fração para descobrir o número, mas não consegui descobrir uma maneira de fazê-la funcionar com o arredondamento dos resultados.


Hmm, isso falha no novo caso de teste. Vou ter que procurar uma solução.
25712 Gareth

4

Python, 154

def r(l):
 v=0
 while 1:
  v+=1;o=[round(y*v/100)for y in l];s=sum(o)
  if s: 
    if all(a==b for a,b in zip(l,[round(y*1000/s)/10for y in o])):return s

+1 Parece bom! ideone.com/k2Mgb . Tentei encontrar um caso patológico para quebrá-lo e não consegui.
Mellamokb

Não consigo gerar ideone devido ao limite de tempo exceder, mas que resultado você obtém [0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,99.6]?
Mellamokb

hmm ... meia hora e o programa ainda está em execução. Eu acho que é seguro dizer que isso é um disjuntor. no entanto, eu não vejo como isso pode ser uma resposta válida porque totaliza 100,5% e não 100%
Blazer

2
1/2000 = 0.05%( 0.1%arredondado) e 1991/2000 = 99.55%( 99.6%arredondado). Portanto, ele totaliza 100%, mas o arredondamento o torna realmente confuso.
grc

3

VBA - 541

Isso tem alguns erros flagrantes, mas foi minha tentativa de encontrar uma solução não trivial / de loop até obter o número certo. Ainda não joguei o jogo completamente, apesar de achar que não há muito a acrescentar a esse respeito. No entanto, eu gastei muito tempo nisso e isso machuca minha cabeça agora. Sem mencionar, as regras provavelmente são muito violadas e se aplicam mais ou menos apenas a esses exemplos.

Isso funciona muito bem em muitos testes simples que eu executei (ou seja, totais totais, 2 ou 3 entradas), mas falha em alguns dos testes apresentados pelo desafio. No entanto, descobri que se você aumentar a precisão decimal da entrada (fora do escopo do desafio), a precisão aumentará.

Grande parte do trabalho envolve encontrar o MDC para o conjunto de números fornecidos, e eu meio que consegui isso Function g(), embora seja com certeza incompleto e provavelmente uma fonte de pelo menos alguns dos erros em minhas saídas.

Entrada é uma sequência de valores delimitada por espaço.

Const q=10^10
Sub a(s)
e=Split(s)
m=1
f=UBound(e)
For i=0 To f
t=1/(e(i)/100)
m=m*t
n=IIf(n>t Or i=0,t,n)
x=IIf(x<t Or i=0,t,x)
Next
h=g(n,x)
i=(n*x)/(h)
If Int(i)=Round(Int(i*q)/q) Then
r=i
ElseIf (n+x)=(n*x) Then
r=(1/(n*x))/h/m
ElseIf x=Int(x) Then
r=x*(f+1)
Else
z=((n+x)+(n*x)+m)*h
y=m/(((m*h)/(f+1))+n)
r=IIf(y>z,z,y)
End If
Debug.Print Round(r)
End Sub
Function g(a,b)
x=Round(Int(a*q)/q,3)
y=Round(Int(b*q)/q,3)
If a Then
If b Then
If x>y Then
g=g(a-b,b)
ElseIf y>x Then
g=g(a,b-a)
Else
g=a
End If
End If
Else
g=b
End If
End Function

Casos de teste (entrada ==> esperado / retornado):

Passed:  

"95 5" ==> 20/20
"90 10" ==> 10/10
"46.7 53.3" ==> 15/15
"4.7 30.9 40.4 23.8" ==> 42/42
"44.4 44.4 11.1" ==> 9/9
"26.7 53.3 20.0" ==> 15/15
"48.4 13.7 21.6 6.5 9.8" ==> 153/153
"0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 99.55" ==> 2000/2000
"0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 98.65" ==> 2000/2000
"0.149925 0.149925 0.149925 0.149925 0.149925 0.149925 0.149925 0.149925 0.149925 98.65067" ==> 667/667


Failed:  

"0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 99.6" ==> 2000/1000
"0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 98.7" ==> 2000/5000
"0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 98.7" ==> 667/1000
"0.14 0.14 0.14 0.14 0.14 0.14 0.14 0.14 0.14 98.65" ==> 667/10000
"0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 97.8" ==> 401/500
"0.24 0.24 0.24 0.24 0.24 0.24 0.24 0.24 0.24 97.75" ==> 401/235
"0.249377 0.249377 0.249377 0.249377 0.249377 0.249377 0.249377 0.249377 0.249377 97.75561" ==> 401/14010

você pode perder 6 bytes através da conversão Debug.Print paraDebug.?
Taylor Scott

2

C # (.NET Core) , 286 bytes

double M(string[]a){var p=a.Select(double.Parse).ToList();var n=p.Select(x=>1d).ToList();var c=2;for(;;){Func<double,double>f=x=>Math.Round(x*1000/c,(MidpointRounding)1)/10;if(n.Select(f).Zip(p,(x,y)=>x==y).All(z=>z)&&c==n.Sum())return c;c++;n=n.Zip(p,(x,y)=>x+(f(x)<y?1:0)).ToList();}}

Experimente online!

Economizou muitos bytes graças a Peter Taylor e Embodiment of Ignorance


Como eu poderia modificar isso para testá-lo em ideone.com?
24712 Gareth

Acho que falta um }no final.
grc

@Gareth Tentei executá-lo no ideone.com, mas acho que ele está usando uma versão do .NET framework anterior à 4.0, porque não reconhece o Zipmétodo Linq .
Cristian Lupascu

@grc Obrigado por apontar isso. Atualizada.
Cristian Lupascu

1
@ Gaffi: Não, o C # possui digitação estrita (como Java), portanto deve ser um booleano. Como 1>0é mais curto que true, é preferível.
precisa saber é o seguinte

0

Python 3 , 140 139 137 bytes

f=lambda l,m=1,i=0,c=0,x=0:round(x*100,1)-l[i]and(x<1and f(l,m,i,c,x+1/m)or f(l,m+1))or l[i+1:]and f(l,m,i+1,c+x)or c+x-1and f(l,m+1)or m

Experimente online!

Dá a resposta certa para os dois primeiros casos de teste e se depara com os limites de recursão do Python para os outros. Isso não é muito surpreendente, pois cada verificação é feita em um novo nível de recursão. É curto, no entanto ...

(Uma explicação das variáveis ​​usadas pode ser encontrada no link TIO)

f=lambda l,m=1,i=0,c=0,x=1:round(x*100,1)-l[i]and(x and f(l,m,i,c,x-1/m)or f(l,m+1))or l[i+1:]and f(l,m,i+1,c+x)or c+x-1and f(l,m+1)or m

deve funcionar para 136 bytes, mas não devido à precisão de flutuação.

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.