Statistik Polling Reverse Engineer


22

pengantar

Dengan serangkaian persentase pilihan dalam jajak pendapat, hitung jumlah pemilih minimum yang harus ada dalam jajak pendapat untuk menghasilkan statistik tersebut.

Contoh: Apa peliharaan kesayangan Anda?

  • Anjing: 44.4%
  • Kucing: 44.4%
  • Mouse: 11.1%

Output: 9(minimum yang mungkin # dari pemilih)

Spesifikasi

Berikut persyaratan untuk program / fungsi Anda:

  • Anda diberi array nilai persentase sebagai input (pada stdin, sebagai argumen fungsi, dll.)
  • Setiap nilai persentase adalah angka yang dibulatkan ke satu tempat desimal (misalnya, 44.4 44.4 11.1).
  • Hitung jumlah pemilih minimum yang mungkin dalam jajak pendapat yang hasilnya akan menghasilkan persentase yang tepat ketika dibulatkan ke satu tempat desimal (pada stdout, atau nilai pengembalian fungsi).
  • Bonus : -15 karakter jika Anda dapat menyelesaikan dengan cara "non-sepele" (yaitu, tidak melibatkan iterasi melalui setiap # pemilih yang mungkin sampai Anda menemukan yang pertama yang berfungsi)

Contoh

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

Mencetak gol

Ini adalah kode-golf, sehingga karakter terpendek yang mungkin menang. Bonus apa pun dikurangi lebih lanjut dari jumlah karakter total.


2
Saya pikir ini bisa dilakukan dengan beberapa kasus canggung untuk pengujian. 26.7 53.3 20.0(4 8 3 dari 15), 48.4 13.7 21.6 6.5 9.8(74 21 33 10 15 dari 153) dll.
Gareth

@ Gareth: Pikiran yang bagus. Diperbarui dengan uji kasus Anda.
mellamokb

tidakkah seharusnya jumlah semua suara menjadi 100%? itu tidak dalam empat testcases terakhir
Ali1S232

@Gajet: Tidak, itu tidak selalu sama dengan 100%. Setiap kali ada pembulatan ke bawah, Anda kehilangan hingga 0.5%dari total, dan setiap kali ada pembulatan ke atas, Anda menambahkan hingga 0.5%total. Empat kasus uji terakhir sengaja dibuat untuk mengeksploitasi fenomena ini secara optimal. Dalam kasus uji pertama yang menghasilkan 2000, masing-masing dari 9 entri pertama mewakili 1suara (dan semuanya dibulatkan 0.5%), sedangkan yang terakhir mewakili 1991suara (dan dibulatkan ke bawah ~ 0.5%). Jika Anda menghitung persentase tersebut secara manual dan membulatkan ke 1 tempat desimal, Anda akan melihat semuanya benar.
mellamokb

Saya berjuang dengan jawaban non-sepele di VBA (mencoba sejauh ini, tidak ada jawaban), tapi saya sedang mengusahakannya!
Gaffi

Jawaban:


2

APL (Dyalog Classic) , 48 43 byte

-5 byte oleh Adám

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

Program penuh mengambil input dari stdin.

Cobalah online! Tautan ke versi dfn.

Tidak disatukan

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

Cobalah online!

  • normalizemembagi ( ÷) semua elemen argumen kanannya ( ) dengan jumlahnya ( +/).
  • round(y)membulatkan y ke 3 tempat desimal dengan memformat ( ) dan kemudian mengevaluasi ( ) setiap elemen y.
  • find_max(y) mengembalikan array dengan 1 di mana maks (y) ditemukan dan 0 di tempat lain.
  • increase(x,y) mengambil x (persentase sasaran) dan y (array total suara saat ini) dan menghitung di mana menambahkan 1 dalam y untuk membawa persentase lebih dekat ke x.
  • vote_totals(x,y) mengambil x (persentase sasaran) dan y (total suara awal) dan mengeksekusi f berulang kali, menambahkan suara sampai persentase putaran ke x.
    • Sintaks f ⍣ gberarti mengeksekusi fberulang kali sampai g(y,f(y))benar. Dalam hal ini kita abaikan f(y).
  • h(x) set y ke 0 (setara dengan array 0s karena vektorisasi), mengeksekusi g, dan menjumlahkan total suara akhir.

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]

Ini berfungsi untuk contoh terakhir sekarang.

Contoh berjalan:

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

Saya pikir ada sesuatu yang salah dalam contoh terakhir Anda; mungkin yang Anda maksud 99.1sebagai nilai terakhir
Cristian Lupascu

2
Saya pikir itu benar tetapi cukup membingungkan. 1/2000 = 0.05%( 0.1%Bulat) dan 1991/2000 = 99.55%( 99.6%Bulat). Jadi, jika ada sepuluh opsi dalam jajak pendapat dan sembilan di antaranya akan dipilih satu kali sementara yang terakhir mendapatkan suara pada tahun 1991, maka itu akan memberikan persentase tersebut.
grc

Kamu benar. Solusi bagus, BTW.
Cristian Lupascu

Saya pikir Anda dapat menyimpan 3 karakter lagi dengan mengikuti tip ini: codegolf.stackexchange.com/a/58/3527
Cristian

Terima kasih, w0lf. Saya telah memperbarui sekarang untuk memasukkan tab. Tab muncul sebagai empat ruang jika ada yang bertanya-tanya.
grc

4

J, 57 karakter

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

Menggunakan metode trivial. Dibutuhkan input dari keyboard. tmembuat tabel pencarian dan baris kedua mencari input di dalam tabel. Saya dapat memberikan penjelasan kode yang diperluas jika ada yang tertarik.

Saya telah melihat ke dalam menggunakan persentase untuk membuat pecahan kemudian mendapatkan bentuk pecahan terendah untuk mencari tahu angka, tetapi saya tidak bisa menemukan cara untuk membuatnya bekerja dengan pembulatan hasil.


Hmm, ini gagal untuk test case baru. Saya harus mencari perbaikan.
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 Terlihat bagus! ideone.com/k2Mgb . Saya mencoba menemukan kasus patologis untuk memecahkannya dan saya tidak bisa.
mellamokb

Saya tidak dapat menghasilkan di ideone karena melebihi batas waktu, tetapi apa hasil yang Anda dapatkan [0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,99.6]?
mellamokb

hmm ... setengah jam dan program masih berjalan. Saya pikir mungkin aman untuk mengatakan itu adalah pemecah. namun, saya tidak melihat bagaimana itu bisa menjadi jawaban yang valid karena totalnya 100,5% dan bukan 100%
Blazer

2
1/2000 = 0.05%( 0.1%Bulat) dan 1991/2000 = 99.55%( 99.6%Bulat). Jadi itu benar-benar total 100%, tetapi pembulatan membuatnya sangat membingungkan.
grc

3

VBA - 541

Ini memiliki beberapa kesalahan mencolok, tetapi itu adalah usaha saya untuk menemukan solusi non-sepele / perulangan-sampai-saya-dapatkan-nomor-yang benar. Saya belum sepenuhnya bermain golf, meskipun saya pikir tidak banyak yang bisa ditambahkan dalam hal itu. Namun, saya telah menghabiskan terlalu banyak waktu untuk hal ini, dan itu menyakitkan kepala saya sekarang. Belum lagi, aturannya mungkin sangat rusak dan berlaku kurang lebih hanya untuk contoh-contoh ini saja.

Ini sangat baik untuk banyak tes sederhana yang saya jalankan, (yaitu bahkan total, 2 atau 3 input) tetapi gagal untuk beberapa tes yang disajikan oleh tantangan. Namun, saya menemukan bahwa jika Anda meningkatkan ketepatan desimal input (di luar lingkup tantangan), akurasi meningkat.

Sebagian besar pekerjaan melibatkan menemukan gcd untuk set angka yang disediakan, dan saya agak berhasil Function g(), meskipun pasti tidak lengkap dan kemungkinan menjadi sumber setidaknya beberapa kesalahan dalam output saya.

Input adalah string nilai yang dibatasi ruang.

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

Testcases (input ==> diharapkan / dikembalikan):

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

Anda dapat kehilangan 6 byte dengan mengonversi Debug.Print keDebug.?
Taylor Scott

2

C # (.NET Core) , 286 byte

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

Cobalah online!

Menyimpan banyak byte berkat Peter Taylor dan Perwujudan Ketidaktahuan


Bagaimana saya bisa memodifikasi ini untuk mengujinya di ideone.com?
Gareth

Saya pikir Anda kehilangan }di akhir.
grc

@ Gareth Saya mencoba untuk menjalankannya di ideone.com, tapi saya pikir itu menggunakan versi .NET framework lebih awal dari 4.0, karena tidak mengenali Zipmetode Linq .
Cristian Lupascu

@ grc Terima kasih telah menunjukkan itu. Diperbarui.
Cristian Lupascu

1
@ Gaffi: Tidak, C # memiliki pengetikan yang ketat (seperti Java) sehingga harus berupa boolean. Karena 1>0lebih pendek daripada true, itu lebih disukai.
mellamokb

0

Python 3 , 140 139 137 byte

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

Cobalah online!

Memberikan jawaban yang tepat untuk dua kasus uji pertama, dan mengalami batas rekursi Python untuk yang lain. Ini tidak terlalu mengejutkan, karena setiap pemeriksaan dilakukan pada tingkat rekursi baru. Pendek, meskipun ...

(Penjelasan tentang variabel yang digunakan dapat ditemukan di tautan 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

harus bekerja untuk 136 byte, tetapi bukan karena presisi float.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.