Обратный Инженер Статистика Опроса


22

Введение

Учитывая набор процентных вариантов в опросе, подсчитайте минимальное число избирателей, которое должно быть в опросе, чтобы сгенерировать эту статистику.

Пример: какой ваш любимый питомец?

  • Собака: 44.4%
  • Кот: 44.4%
  • Мышь: 11.1%

Выход: 9 (минимально возможное число избирателей)

Спекуляции

Вот требования к вашей программе / функции:

  • В качестве входных данных вы получаете массив значений в процентах (для стандартного ввода, в качестве аргумента функции и т. Д.).
  • Каждое процентное значение представляет собой число, округленное до одного десятичного знака (например, 44.4 44.4 11.1).
  • Вычислите минимально возможное число избирателей в опросе, результаты которых позволят получить эти точные проценты при округлении до одного знака после запятой (по стандартному выводу или возвращаемому значению функции).
  • Бонус : -15 символов, если вы можете решить «нетривиальным» способом (то есть, не включает в себя итерацию по каждому возможному числу избирателей, пока вы не найдете первый, который работает)

пример

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

счет

Это код-гольф, поэтому выигрывают самые короткие персонажи. Любые бонусы вычитаются из общего количества персонажей.


2
Я думаю, что это может быть связано с еще несколькими неудобными случаями для тестирования. 26.7 53.3 20.0(4 8 3 из 15), 48.4 13.7 21.6 6.5 9.8(74 21 33 10 15 из 153) и т. Д.
Гарет

@ Гарет: Хорошая мысль. Обновлено с вашими тестами.
mellamokb

не должна ли сумма всех голосов быть 100%? это не в последних четырех
тестовых случаях

@Gajet: Нет, это не всегда равно 100%. Каждый раз, когда происходит округление, вы теряете до 0.5%суммы итога, и каждый раз, когда происходит округление, вы складываете сумму до 0.5%суммы. Последние четыре контрольных примера были специально созданы для оптимального использования этого явления. В первом тестовом примере, который заканчивается 2000, каждая из первых 9 записей представляет 1голос (и все округляются в 0.5%большую сторону), тогда как последняя представляет 1991голоса (и округляется в меньшую сторону ~ 0.5%). Если вы посчитаете эти проценты вручную и округлите до 1 десятичного знака, вы увидите, что все они верны.
mellamokb

Я борюсь с нетривиальным ответом в VBA (пытаясь до сих пор, не было ни одного), но я работаю над этим!
Гаффи

Ответы:


2

APL (Дьялог Классик) , 48 43 байта

-5 байт от Адама

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

Полная программа ввода от стандартного ввода.

Попробуйте онлайн!Ссылка на версию DFN.

Ungolfed

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

Попробуйте онлайн!

  • normalizeделит ( ÷) все элементы своего правого аргумента ( ) на сумму (+/ ).
  • round(y)округляет y до 3 знаков после запятой форматированием ( ) и затем вычислением ( ) каждый элемент из y.
  • find_max(y) возвращает массив с 1, где max (y) найдено и 0 в другом месте.
  • increase(x,y) берет x (целевые проценты) и y (массив текущих итогов голосования) и вычисляет, куда добавить 1 в y, чтобы приблизить проценты к x.
  • vote_totals(x,y) берет x (целевые проценты) и y (начальные итоги голосования) и выполняет f повторно, добавляя голоса до округления процентов до x.
    • Синтаксис f ⍣ gозначает выполнять fнесколько раз, пока не g(y,f(y))станет истиной. В этом случае мы игнорируем f(y).
  • h(x) устанавливает y в 0 (эквивалентно массиву 0 с из-за векторизации), выполняет g и суммирует итоговые итоги голосования.

7

Питон, 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]

Теперь это работает для последнего примера.

Пример работы:

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

Я думаю, что-то может быть не так в вашем последнем примере; возможно, вы имели 99.1в виду последнее значение
Кристиан Лупаску

2
Я думаю, что это правильно, но это довольно запутанно. 1/2000 = 0.05%( 0.1%округлено) и 1991/2000 = 99.55%( 99.6%округлено). Так что, если в опросе есть десять вариантов, и за них проголосуют девять из них, в то время как последний получит голоса 1991 года, тогда он даст эти проценты.
grc

Вы правы. Отличное решение, кстати.
Кристиан Лупаску

Я думаю, что вы можете сохранить еще 3 символа, следуя этому совету
Кристиан Лупаску

Спасибо, w0lf. Я обновил его сейчас, чтобы включить вкладки. Вкладки отображаются как четыре пробела, если кому-то интересно.
grc

4

J, 57 знаков

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

Использовал тривиальный метод. Требуется ввод с клавиатуры.tсоздает таблицу поиска, а вторая строка ищет входные данные в таблице. Я могу предоставить расширенное объяснение кода, если кому-то интересно.

Я рассмотрел использование процента для создания дроби, а затем получил наименьшую форму дроби, чтобы вычислить число, но я не мог найти способ заставить его работать с округлением результатов.


Хм, это терпит неудачу для нового теста. Я должен искать исправление.
Гарет

4

Питон, 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 выглядит хорошо! ideone.com/k2Mgb . Я пытался найти патологический случай, чтобы сломать его, и я не мог.
mellamokb

Я не могу генерировать на ideone из-за превышения срока, но какой результат вы получите [0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,99.6]?
mellamokb

хм ... полчаса и программа все еще работает. Я думаю, что можно с уверенностью сказать, что это брейкер. однако, я не понимаю, как это может быть правильным ответом, потому что он составляет 100,5%, а не 100%
Blazer

2
1/2000 = 0.05%( 0.1%округлено) и 1991/2000 = 99.55%( 99.6%округлено). Так что на самом деле это 100%, но округление делает это действительно запутанным.
grc

3

VBA - 541

В этом есть некоторые явные ошибки, но это была моя попытка найти нетривиальное решение, пока я не получу правильное число. Я не полностью играл в гольф, хотя я не думаю, что есть что добавить в этом отношении. Однако я потратил слишком много времени на это, и сейчас у меня болит голова. Не говоря уже о том, что правила, вероятно, очень нарушены и применяются более или менее только к этим примерам.

Это очень хорошо подходит для многих простых тестов, которые я выполнял (т. Е. Даже для итогов, 2 или 3 входных данных), но не проходит для некоторых тестов, представленных в ходе испытания. Тем не менее, я обнаружил, что если вы увеличите десятичную точность ввода (вне рамок задачи), точность улучшится.

Большая часть работы включает в себя поиск gcd для набора предоставленных чисел, и я вроде как справился с этим Function g(), хотя он, безусловно, неполон и, вероятно, является источником по крайней мере некоторых ошибок в моих выходных данных.

Ввод - это строка значений, разделенных пробелами.

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

Тестовые случаи (входные данные ==> ожидаемые / возвращаемые):

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

Вы можете потерять 6 байтов, преобразовав Debug.Print вDebug.?
Тейлор Скотт

2

C # (.NET Core) , 286 байт

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

Попробуйте онлайн!

Сохранено много байтов благодаря Питеру Тейлору и Embodiment of Ignorance


Как я могу изменить это, чтобы проверить это на ideone.com?
Гарет

Я думаю, что вам не хватает }в конце.
grc

@ Гарет Я пытался выполнить его на ideone.com, но я думаю, что он использует версию платформы .NET, более раннюю, чем 4.0, потому что он не распознает Zipметод Linq .
Кристиан Лупаску

@grc Спасибо за указание на это. Обновлено.
Кристиан Лупаску

1
@Gaffi: Нет, C # имеет строгую типизацию (как Java), поэтому он должен быть логическим. Так 1>0как короче true, это предпочтительно.
mellamokb

0

Python 3 , 140 139 137 байт

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

Попробуйте онлайн!

Дает правильный ответ для первых двух тестовых случаев и выходит за пределы рекурсии Python для остальных. Это не очень удивительно, поскольку каждая проверка выполняется на новом уровне рекурсии. Это коротко, хотя ...

(Объяснение используемых переменных можно найти в ссылке 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

должен работать на 136 байтов, но не из-за точности с плавающей точкой.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.