Statystyki odpytywania inżyniera wstecznego

22

Wprowadzenie

Biorąc pod uwagę zestaw procentowy wyborów w ankiecie, oblicz minimalną liczbę wyborców, którzy muszą być w ankiecie, aby wygenerować te statystyki.

Przykład: jakie jest twoje ulubione zwierzę domowe?

  • Pies: 44.4%
  • Kot: 44.4%
  • Mysz: 11.1%

Wynik: 9(minimalna możliwa liczba wyborców)

Okular

Oto wymagania dotyczące Twojego programu / funkcji:

  • Otrzymujesz tablicę wartości procentowych jako dane wejściowe (na stdin, jako argument funkcji itp.)
  • Każda wartość procentowa jest liczbą zaokrągloną do jednego miejsca po przecinku (np 44.4 44.4 11.1.).
  • Oblicz minimalną możliwą liczbę wyborców w ankiecie, których wyniki dałyby dokładnie te wartości procentowe po zaokrągleniu do jednego miejsca po przecinku (na wyjściu standardowym lub wartości zwracanej przez funkcję).
  • Premia : -15 znaków, jeśli możesz rozwiązać w sposób „nietrywialny” (tzn. Nie wymaga iteracji przez każdą możliwą liczbę wyborców, dopóki nie znajdziesz pierwszego, który działa)

Przykład

>./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

Punktacja

To jest golf golfowy, więc wygrywa najkrótsza możliwa postać. Wszelkie bonusy są odejmowane od całkowitej liczby postaci.

mellamokb
źródło
2
Myślę, że można to zrobić z kilkoma bardziej niezręcznymi przypadkami do testowania. 26.7 53.3 20.0(4 8 3 z 15), 48.4 13.7 21.6 6.5 9.8(74 21 33 10 15 z 153) itd.
Gareth,
@Gareth: Dobra myśl. Zaktualizowany o przypadki testowe.
mellamokb
czy suma wszystkich głosów nie powinna wynosić 100%? nie ma go w czterech ostatnich
testach
@Gajet: Nie, nie zawsze wynosi 100%. Za każdym razem, gdy następuje zaokrąglenie w dół, tracisz do 0.5%z sumy i za każdym razem, gdy następuje zaokrąglanie w górę, sumujesz 0.5%do sumy. Ostatnie cztery przypadki testowe zostały celowo skonstruowane w celu optymalnego wykorzystania tego zjawiska. W pierwszym przypadku testowym, który daje wynik 2000, każdy z pierwszych 9 wpisów reprezentuje 1głos (i wszystkie są zaokrąglane w górę 0.5%), podczas gdy ostatni reprezentuje 1991głosy (i jest zaokrąglany w dół ~ 0.5%). Jeśli obliczasz te wartości procentowe ręcznie i zaokrąglasz do 1 miejsca po przecinku, zobaczysz, że wszystkie są poprawne.
mellamokb
Walczę z nietrywialną odpowiedzią w VBA (próbuję do tej pory nie było żadnej), ale pracuję nad tym!
Gaffi

Odpowiedzi:

2

APL (Dyalog Classic) , 48 43 bajtów

-5 bajtów autorstwa Adáma

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

Pełny program pobiera dane wejściowe ze standardowego wejścia.

Wypróbuj online! Link jest do wersji dfn.

Nie golfił

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

Wypróbuj online!

  • normalizedzieli ( ÷) wszystkie elementy swojego prawego argumentu ( ) przez sumę ( +/).
  • round(y)zaokrągla y do 3 miejsc po przecinku, formatując ( ), a następnie oceniając ( ) każdy element y.
  • find_max(y) zwraca tablicę z 1, gdzie znaleziono max (y) i 0 w innym miejscu.
  • increase(x,y) bierze x (procent bramek) iy (tablica bieżących sum głosów) i oblicza, gdzie dodać 1 w y, aby przybliżyć wartości procentowe do x.
  • vote_totals(x,y) przyjmuje x (procent bramek) i y (sumy głosów początkowych) i wykonuje f wielokrotnie, dodając głosy aż do zaokrągleń procentowych do x.
    • Składnia f ⍣ goznacza fpowtarzanie do momentu, aż g(y,f(y))będzie prawdziwe. W tym przypadku ignorujemy f(y).
  • h(x) ustawia y na 0 (odpowiednik tablicy zer z powodu wektoryzacji), wykonuje g i sumuje końcowe głosy.
lirtosiast
źródło
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]

Działa teraz dla ostatniego przykładu.

Przykładowe przebiegi:

>>> 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
grc
źródło
Myślę, że coś może być nie tak w twoim ostatnim przykładzie; być może chodziło Ci 99.1o ostatnią wartość
Cristian Lupascu,
2
Myślę, że to prawda, ale jest dość mylące. 1/2000 = 0.05%( 0.1%zaokrąglony) i 1991/2000 = 99.55%( 99.6%zaokrąglony). Jeśli więc w ankiecie jest dziesięć opcji, a dziewięć z nich zostanie poddanych głosowaniu raz, a ostatnia uzyska 1991 głosów, to dałoby to te wartości procentowe.
grc,
Masz rację. Świetne rozwiązanie, BTW.
Cristian Lupascu
Myślę, że możesz zapisać 3 dodatkowe znaki, postępując zgodnie z tą wskazówką: codegolf.stackexchange.com/a/58/3527
Cristian Lupascu
Dzięki, w0lf. Zaktualizowałem go teraz, aby zawierał karty. Zakładki są wyświetlane jako cztery spacje, jeśli ktoś się zastanawia.
grc
4

J, 57 znaków

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

Zastosowano trywialną metodę. Wymaga danych z klawiatury. ttworzy tabelę przeglądową, a druga linia szuka danych wejściowych w tabeli. Jeśli ktoś jest zainteresowany, mogę dostarczyć rozszerzone wyjaśnienie kodu.

Zastanawiałem się nad wykorzystaniem procentu do utworzenia ułamka, a następnie otrzymałem najniższą formę ułamka, aby obliczyć liczbę, ale nie mogłem wymyślić sposobu, aby działał z zaokrąglaniem wyników.

Gareth
źródło
Hmm, to się nie powiedzie w przypadku nowego przypadku testowego. Będę musiał szukać poprawki.
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
Blezer
źródło
+1 Wygląda dobrze! ideone.com/k2Mgb . Próbowałem znaleźć patologiczny przypadek, aby go złamać, ale nie mogłem.
mellamokb
Nie mogę generować na ideonie z powodu przekroczenia limitu czasu, ale jaki masz wynik [0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,99.6]?
mellamokb
hmm ... pół godziny, a program nadal działa. Myślę, że prawdopodobnie bezpiecznie jest powiedzieć, że to łamacz. nie wiem jednak, jak to może być poprawna odpowiedź, ponieważ wynosi ona 100,5%, a nie 100%
Blazer
2
1/2000 = 0.05%( 0.1%zaokrąglony) i 1991/2000 = 99.55%( 99.6%zaokrąglony). Tak więc w rzeczywistości wynosi 100%, ale zaokrąglenie sprawia, że ​​jest to naprawdę mylące.
grc,
3

VBA - 541

Wystąpiły pewne rażące błędy, ale to była moja próba znalezienia rozwiązania, które nie jest trywialne / zapętla się, aż dostanę odpowiednią liczbę. Nie w pełni grałem w golfa, choć nie sądzę, aby można było wiele dodać w tym względzie. Jednak spędziłem za dużo czasu i boli mnie to teraz. Nie wspominając o tym, że reguły są prawdopodobnie bardzo złamane i dotyczą mniej więcej tylko tych przykładów.

Działa to bardzo dobrze w przypadku wielu prostych testów, które przeprowadziłem (tj. Nawet sumy, 2 lub 3 dane wejściowe), ale nie udaje się to w przypadku niektórych testów przedstawionych przez wyzwanie. Odkryłem jednak, że jeśli zwiększysz dokładność dziesiętną danych wejściowych (poza zakresem wyzwania), dokładność poprawi się.

Znaczna część pracy polega na znalezieniu gcd dla podanego zestawu liczb, a ja w pewnym sensie to przeszedłem Function g(), chociaż z pewnością jest niekompletne i prawdopodobnie źródłem przynajmniej niektórych błędów w moich wynikach.

Dane wejściowe to ciąg wartości rozdzielany spacjami.

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

Przypadki testowe (dane wejściowe ==> oczekiwane / zwrócone):

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
Gaffi
źródło
możesz stracić 6 bajtów, konwertując Debug.Print naDebug.?
Taylor Scott
2

C # (.NET Core) , 286 bajtów

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();}}

Wypróbuj online!

Zaoszczędzono wiele bajtów dzięki Peterowi Taylorowi i Embodiment of Ignorance

Cristian Lupascu
źródło
Jak mogę to zmodyfikować, aby przetestować na ideone.com?
Gareth
Myślę, że }na końcu brakuje .
grc
@Gareth Próbowałem uruchomić go na ideone.com, ale myślę, że używa wersji .NET Framework wcześniejszej niż 4.0, ponieważ nie rozpoznaje Zipmetody Linq .
Cristian Lupascu
@grc Dziękujemy za zwrócenie na to uwagi. Zaktualizowano
Cristian Lupascu
1
@Gaffi: Nie, C # ma ścisłe pisanie (jak Java), więc musi być logiczną. Ponieważ 1>0jest krótszy niż true, jest preferowany.
mellamokb
0

Python 3 , 140 139 137 bajtów

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

Wypróbuj online!

Podaje prawidłową odpowiedź dla dwóch pierwszych przypadków testowych i dla innych odpowiada limitom rekurencji w Pythonie. Nie jest to bardzo zaskakujące, ponieważ każda kontrola jest przeprowadzana na nowym poziomie rekurencji. Jest jednak krótki ...

(Wyjaśnienie używanych zmiennych można znaleźć w linku 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

powinien działać dla 136 bajtów, ale nie działa z powodu precyzji zmiennoprzecinkowej.

ArBo
źródło