Статистика обернених інженерів


22

Вступ

Враховуючи набір відсотків вибору у опитуванні, обчисліть мінімальну кількість виборців, яка повинна бути в опитуванні, щоб створити цю статистику.

Приклад: Який ваш улюблений улюбленець?

  • Пес: 44.4%
  • Кіт: 44.4%
  • Миша: 11.1%

Результат: 9(мінімально можлива кількість виборців)

Технічні характеристики

Ось вимоги до вашої програми / функції:

  • Вам надається масив відсоткових значень як вхідних даних (на stdin, як аргумент функції тощо)
  • Кожне процентне значення - це число, округлене до одного десяткового знака (наприклад, 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) тощо
Гарет

@Gareth: Гарна думка. Оновлено ваші тестові приклади.
mellamokb

чи не повинна сума всіх голосів бути 100%? його немає в останніх чотирьох
тестах

@Gajet: Ні, це не завжди дорівнює 100%. Кожен раз, коли відбувається округлення вниз, ви втрачаєте до 0.5%загальної суми, і кожного разу, коли відбувається округлення, ви додаєте 0.5%до загальної суми. Останні чотири тестові справи були спеціально побудовані для оптимального використання цього явища. У першому тестовому випадку, в результаті якого 2000кожен із перших 9 записів представляє 1голос (і всі округляються 0.5%), тоді як останній - 1991голоси (і округляються вниз ~ 0.5%). Якщо ви вирахуєте ці відсотки вручну і округлите до 1 десяткового знака, ви побачите, що вони все правильно.
mellamokb

Я борюся з нетривіальною відповіддю у VBA (намагаюся з тих пір, жодної не було), але я над цим працюю!
Гаффі

Відповіді:


2

APL (Dyalog Classic) , 48 43 байти

-5 байт від Adám

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

Повна програма, що приймає дані від stdin.

Спробуйте в Інтернеті! Посилання на версію dfn.

Безумовно

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 (еквівалентно масиву 0s за рахунок векторизації), виконує 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

Ти правий. Чудове рішення, BTW.
Крістіан Лупаску

Я думаю, що ви можете зберегти ще 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();}}

Спробуйте в Інтернеті!

Збережено багато байтів завдяки Пітеру Тейлору та Втіленню Невігластва


Як я міг змінити це, щоб перевірити його на ideone.com?
Гарет

Я думаю, що ти пропускаєш }наприкінці.
гр.кр.

@Gareth Я спробував виконати його на ideone.com, але я думаю, що він використовує версію .NET Framework раніше, ніж 4.0, оскільки він не розпізнає Zipметод Linq .
Крістіан Лупаску

@grc Дякуємо, що вказали на це. Оновлено.
Крістіан Лупаску

1
@Gaffi: Ні, C # має чітке введення тексту (як Java), тому воно повинно бути булевим. Оскільки 1>0він коротший true, він є кращим.
mellamokb

0

Пітон 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.