リバースエンジニアポーリング統計


22

前書き

投票の選択肢の割合のセットが与えられたら、それらの統計を生成するために投票に含まれる必要がある有権者の最小数を計算します。

例:お気に入りのペットは何ですか?

  • 犬: 44.4%
  • ネコ: 44.4%
  • マウス: 11.1%

出力:(9投票者の可能な最小数)

スペック

プログラム/機能の要件は次のとおりです。

  • 入力としてパーセンテージ値の配列が与えられます(標準入力、関数の引数など)。
  • 各パーセント値は、小数点以下1桁に丸められた数値です(たとえば、 44.4 44.4 11.1
  • (stdoutまたは関数の戻り値で)小数点以下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 153の15)など
ガレス

@Gareth:いい考えだ。テストケースで更新されました。
mellamokb

すべての票の合計が100%であってはなりませんか?最後の4つのテストケースではありません
Ali1S232

@Gajet:いいえ、100%とは限りません。切り捨てが行われる0.5%たびに合計から合計が失われ、切り上げが行われるたび0.5%に合計が合計されます。最後の4つのテストケースは、この現象を最適に活用するために意図的に作成されました。結果の最初のテストケースで2000は、最初の9つのエントリはそれぞれ1投票を表し(すべて切り上げられます0.5%)、最後のエントリは投票を表します1991(切り捨てられます〜0.5%)。これらのパーセンテージを手動で計算し、小数点以下1桁に丸めると、すべて正しいことがわかります。
mellamokb

私はVBAの重要な答えに苦労しています(これまで試していましたが、何もありませんでした)が、私はそれに取り組んでいます!
ガフィ

回答:


2

APL(Dyalog Classic) 48 43バイト

Adámによる -5バイト

+/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桁に丸めてから評価(各要素を)するます。
  • find_max(y) max(y)が見つかった場合は1、その他の場合は0の配列を返します。
  • increase(x,y) x(目標パーセンテージ)とy(現在の投票合計の配列)を取り、パーセンテージをxに近づけるためにyの1を追加する場所を計算します。
  • vote_totals(x,y) x(目標の割合)とy(開始票の合計)を取り、fを繰り返し実行し、割合がxに丸められるまで票を追加します。
    • 構文f ⍣ gは、trueになるfまで繰り返し実行することを意味しg(y,f(y))ます。この場合、無視しf(y)ます。
  • h(x) yを0に設定し(ベクトル化による0の配列に相当)、gを実行し、最終投票の合計を合計します。

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]

これで、最後の例で機能します。

実行例:

>>> 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%丸められた)。したがって、投票に10個のオプションがあり、そのうちの9個が最後に1991票を獲得する間に一度投票されると、それらの割合が得られます。
-grc

あなたが正しい。素晴らしいソリューション、ところで。
クリスチャンルパスク

このヒントに従うことで、さらに3文字を保存できると思います。codegolf.stackexchange.com
Cristian Lupascu

ありがとう、w0lf。タブを含めるように更新しました。誰かが疑問に思っている場合、タブは4つのスペースとして表示されます。
-grc

4

J、57文字

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

簡単な方法を使用しました。キーボードから入力を受け取ります。tルックアップテーブルを作成し、2行目はテーブル内の入力を探します。興味のある方は、コードの詳細な説明を提供できます。

割合を使用して分数を作成し、分数の最も低い形式を取得して数値を調べることを検討しましたが、結果の丸めで機能させる方法を見つけることができませんでした。


うーん、これは新しいテストケースでは失敗します。修正を探す必要があります。
ガレス

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よさそう!ideone.com/k2Mgb。私はそれを打破するための病理学的なケースを見つけようとしましたが、できませんでした。
mellamokb

時間制限を超えているため、イデオンでは生成できませんが、どのような結果が得られ[0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,99.6]ますか?
mellamokb

うーん... 30分、プログラムはまだ実行中です。おそらくそれがブレーカーだと言っても安全だと思います。ただし、合計が100%ではなく100.5%であるため、それが有効な答えになる方法はわかりません。
ブレイザー

2
1/2000 = 0.05%0.1%丸められた)および1991/2000 = 99.55%99.6%丸められた)。したがって、実際には合計100%になりますが、丸めにより、非常に混乱します。
-grc

3

VBA-541

これにはいくつかの明白なエラーがありますが、それは私が正しい番号を取得するまで非自明/ループを見つけるための私の試みでした。私はそれを完全にゴルフしたわけではありませんが、その点に関して追加すべきことはあまりないと思います。しかし、私はこれに時間を費やしすぎており、今では頭が痛いです。言うまでもなく、ルールはおそらく非常に壊れており、これらの例にのみ多少適用されます。

これは、私が実行した多くの単純なテスト(つまり、合計2、3回の入力)で非常にうまくいきますが、チャレンジによって提示されたいくつかのテストでは失敗します。ただし、入力の10進精度(チャレンジの範囲外)を上げると、精度が向上することがわかりました。

作業の多くは、提供された一連の数値の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

に変換するDebug.Print ことにより、6バイト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でテストするためにこれをどのように変更できますか?
ガレス

}最後に行方不明になっていると思います。
-grc

@Gareth ideone.comで実行しようとしましたが、Linq Zipメソッドを認識しないため、4.0より前のバージョンの.NETフレームワークを使用していると思います。
クリスチャンルパスク

@grcそれを指摘してくれてありがとう。更新しました。
クリスチャンルパスク

1
@Gaffi:いいえ、C#には厳密な型指定(Javaなど)があるため、ブール値でなければなりません。以来1>0よりも短くなってtrue、それが好ましいです。
mellamokb

0

Pythonの3140の 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

オンラインでお試しください!

最初の2つのテストケースに正しい答えを与え、他のテストケースの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バイトで動作するはずですが、浮動小数点精度のためではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.