Java, 806,899 dolar
Bu 2501 tur denemesinden. Hala onu optimize etmeye çalışıyorum. İki sınıf yazdım, bir sarmalayıcı ve bir oyuncu. Sarıcı, oynatıcıyı zarf sayısıyla (her zaman için 10000 olan) başlatır ve sonra yöntemi takeQ
üst zarfın değeriyle çağırır . Oyuncu daha sonra true
alırlarsa, false
geçerse geri döner .
oyuncu
import java.lang.Math;
public class Player {
public int[] V;
public Player(int s) {
V = new int[s];
for (int i = 0; i < V.length; i++) {
V[i] = i + 1;
}
// System.out.println();
}
public boolean takeQ(int x) {
// System.out.println("look " + x);
// http://www.programmingsimplified.com/java/source-code/java-program-for-binary-search
int first = 0;
int last = V.length - 1;
int middle = (first + last) / 2;
int search = x;
while (first <= last) {
if (V[middle] < search)
first = middle + 1;
else if (V[middle] == search)
break;
else
last = middle - 1;
middle = (first + last) / 2;
}
int i = middle;
if (first > last) {
// System.out.println(" PASS");
return false; // value not found, so the envelope must not be in the list
// of acceptable ones
}
int[] newVp = new int[V.length - 1];
for (int j = 0; j < i; j++) {
newVp[j] = V[j];
}
for (int j = i + 1; j < V.length; j++) {
newVp[j - 1] = V[j];
}
double pass = calcVal(newVp);
int[] newVt = new int[V.length - i - 1];
for (int j = i + 1; j < V.length; j++) {
newVt[j - i - 1] = V[j];
}
double take = V[i] + calcVal(newVt);
// System.out.println(" take " + take);
// System.out.println(" pass " + pass);
if (take > pass) {
V = newVt;
// System.out.println(" TAKE");
return true;
} else {
V = newVp;
// System.out.println(" PASS");
return false;
}
}
public double calcVal(int[] list) {
double total = 0;
for (int i : list) {
total += i;
}
double ent = 0;
for (int i : list) {
if (i > 0) {
ent -= i / total * Math.log(i / total);
}
}
// System.out.println(" total " + total);
// System.out.println(" entro " + Math.exp(ent));
// System.out.println(" count " + list.length);
return total * (Math.pow(Math.exp(ent), -0.5) * 4.0 / 3);
}
}
sarıcı
import java.lang.Math;
import java.util.Random;
import java.util.ArrayList;
import java.util.Collections;
public class Controller {
public static void main(String[] args) {
int size = 10000;
int rounds = 2501;
ArrayList<Integer> results = new ArrayList<Integer>();
int[] envelopes = new int[size];
for (int i = 0; i < envelopes.length; i++) {
envelopes[i] = i + 1;
}
for (int round = 0; round < rounds; round++) {
shuffleArray(envelopes);
Player p = new Player(size);
int cutoff = 0;
int winnings = 0;
for (int i = 0; i < envelopes.length; i++) {
boolean take = p.takeQ(envelopes[i]);
if (take && envelopes[i] >= cutoff) {
winnings += envelopes[i];
cutoff = envelopes[i];
}
}
results.add(winnings);
}
Collections.sort(results);
System.out.println(
rounds + " rounds, median is " + results.get(results.size() / 2));
}
// stol... I mean borrowed from
// http://stackoverflow.com/questions/1519736/random-shuffling-of-an-array
static Random rnd = new Random();
static void shuffleArray(int[] ar) {
for (int i = ar.length - 1; i > 0; i--) {
int index = rnd.nextInt(i + 1);
// Simple swap
int a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}
}
}
Optimizasyonları bitirdikten sonra yakında daha ayrıntılı bir açıklama gelecek.
Temel fikir, belirli bir zarf kümesinden bir oyun oynamanın ödülünü tahmin edebilmektir. Geçerli zarf kümesi {2,4,5,7,8,9} ve üst zarf 5 ise, iki olasılık vardır:
- Beşi al ve {7,8,9} ile bir oyun oyna
- 5'i geç ve {2,4,7,8,9} oyununu oyna
Beklenen {7,8,9} ödülünü hesaplarsak ve bunu {2,4,7,8,9} beklenen ödül ile karşılaştırırsak, 5'i almaya değip değmeyeceğini söyleyebiliriz.
Şimdi soru, {2,4,7,8,9} gibi bir dizi zarf verildiğinde beklenen değer nedir? Beklenen değerin, kümedeki toplam para miktarıyla orantılı olduğunu, ancak paranın bölündüğü zarf sayısının karekökü ile ters orantılı olduğunu gördüm. Bu, tüm zarfların neredeyse aynı değerde olduğu birkaç küçük oyun oynamaktan "mükemmel" bir şeydi.
Bir sonraki sorun, " etkili zarf sayısının " nasıl belirleneceğidir . Her durumda, zarf sayısı tam olarak gördüklerinizi ve yaptıklarınızı takip ederek bilinir. {234,235,236} gibi bir şey kesinlikle üç zarf, {231,232,233,234,235} kesinlikle 5, ancak {1,2,234,235,236} gerçekten 3 sayılmalı, çünkü 5 ve 1 zarf neredeyse hiç değersizdir, ve 234'te hiç PASS yapmazsınız. daha sonra 1 veya 2 puan alabilirsin. Etkili zarf sayısını belirlemek için Shannon entropy'i kullanma fikrim vardı.
Hesaplamalarımı zarfın değerlerinin belli bir aralıkta eşit dağıldığı durumlara hedefledim, bu da oyun sırasında olan şey. {2,4,7,8,9} alırsam ve bunu olasılık dağılımı olarak kabul edersem, entropisi 1.50242'dir. Sonra exp()
etkili zarf sayısı olarak 4.49254 almak.
{2,4,7,8,9} 'dan tahmini ödül 30 * 4.4925^-0.5 * 4/3 = 18.87
Kesin sayı 18.1167
.
Bu kesin bir tahmin değil, ancak zarflar belli aralıklarla eşit olarak dağıtıldığında verinin ne kadar iyi uyduğuyla gerçekten gurur duyuyorum. Doğru çarpandan emin değilim (şimdilik 4/3 kullanıyorum), ancak burada çarpanı hariç tutan bir veri tablosu var.
Set of Envelopes Total * (e^entropy)^-0.5 Actual Score
{1,2,3,4,5,6,7,8,9,10} 18.759 25.473
{2,3,4,5,6,7,8,9,10,11} 21.657 29.279
{3,4,5,6,7,8,9,10,11,12} 24.648 33.125
{4,5,6,7,8,9,10,11,12,13} 27.687 37.002
{5,6,7,8,9,10,11,12,13,14} 30.757 40.945
{6,7,8,9,10,11,12,13,14,15} 33.846 44.900
{7,8,9,10,11,12,13,14,15,16} 36.949 48.871
{8,9,10,11,12,13,14,15,16,17} 40.062 52.857
{9,10,11,12,13,14,15,16,17,18} 43.183 56.848
{10,11,12,13,14,15,16,17,18,19} 46.311 60.857
Beklenen ve gerçekleşen arasındaki doğrusal regresyon , 0.999994 olan bir R ^ 2 değeri verir .
Bu cevabı geliştirmek için bir sonraki adımım zarf sayısı azalıyorsa, zarfların yaklaşık olarak eşit dağılmadığı ve problemin granülleşmeye başladığı zamanki tahminleri iyileştirmektir.
Düzenleme: Eğer bu bitcoin değerinde görülüyorsa, adresimi yeni aldım 1PZ65cXxUEEcGwd7E8i7g6qmvLDGqZ5JWg
. Teşekkürler! (Bu, meydan yazıcısının ödülleri dağıttığı zamandan beri buradaydı.)