Java, 806 899 $
Il s'agit d'un essai de 2501 tours. Je travaille toujours sur son optimisation. J'ai écrit deux classes, un wrapper et un joueur. L'encapsuleur instancie le lecteur avec le nombre d'enveloppes (toujours 10000 pour la vraie chose), puis appelle la méthode takeQ
avec la valeur de l'enveloppe supérieure. Le joueur revient ensuite true
s'il le prend, false
s'il le passe.
Joueur
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);
}
}
Wrapper
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;
}
}
}
Une explication plus détaillée arrivera bientôt, une fois les optimisations terminées.
L'idée centrale est de pouvoir estimer la récompense d'un jeu à partir d'un ensemble d'enveloppes donné. Si le jeu d'enveloppes actuel est {2,4,5,7,8,9} et que l'enveloppe supérieure est le 5, il y a deux possibilités:
- Prenez les 5 et jouez avec {7,8,9}
- Passez les 5 et jouez une partie de {2,4,7,8,9}
Si nous calculons la récompense attendue de {7,8,9} et la comparons à la récompense attendue de {2,4,7,8,9}, nous serons en mesure de dire si prendre le 5 en vaut la peine.
Maintenant, la question est, étant donné un ensemble d'enveloppes comme {2,4,7,8,9} quelle est la valeur attendue? J'ai trouvé que la valeur attendue semble être proportionnelle au montant total de l'argent dans l'ensemble, mais inversement proportionnelle à la racine carrée du nombre d'enveloppes dans lesquelles l'argent est divisé. Cela venait de "parfaitement" jouer à plusieurs petits jeux dans lesquels toutes les enveloppes ont une valeur presque identique.
Le problème suivant est de savoir comment déterminer le " nombre effectif d'enveloppes». Dans tous les cas, le nombre d'enveloppes est connu exactement en gardant une trace de ce que vous avez vu et fait. Quelque chose comme {234,235,236} est certainement trois enveloppes, {231,232,233,234,235} est certainement 5, mais {1,2,234,235,236} devrait vraiment compter comme 3 et non 5 enveloppes car les 1 et 2 sont presque sans valeur, et vous ne PASSERIEZ JAMAIS sur un 234 donc vous pourriez plus tard prendre un 1 ou 2. J'ai eu l'idée d'utiliser l'entropie de Shannon pour déterminer le nombre effectif d'enveloppes.
J'ai ciblé mes calculs sur des situations où les valeurs de l'enveloppe sont uniformément réparties sur un certain intervalle, ce qui se produit pendant le jeu. Si je prends {2,4,7,8,9} et que je la traite comme une distribution de probabilité, son entropie est de 1,50242. Alors je faisexp()
pour obtenir 4,49254 comme nombre effectif d'enveloppes.
La récompense estimée de {2,4,7,8,9} est 30 * 4.4925^-0.5 * 4/3 = 18.87
Le nombre exact est 18.1167
.
Ce n'est pas une estimation exacte, mais je suis vraiment très fier de la façon dont cela correspond aux données lorsque les enveloppes sont réparties uniformément sur un intervalle. Je ne suis pas sûr du bon multiplicateur (j'utilise 4/3 pour l'instant) mais voici un tableau de données excluant le multiplicateur.
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
La régression linéaire entre les valeurs attendues et réelles donne une valeur R ^ 2 de 0,999994 .
Ma prochaine étape pour améliorer cette réponse consiste à améliorer l'estimation lorsque le nombre d'enveloppes commence à devenir petit, c'est-à-dire lorsque les enveloppes ne sont pas réparties de manière approximativement uniforme et lorsque le problème commence à devenir granuleux.
Edit: Si cela est jugé digne des bitcoins, je viens de recevoir une adresse à 1PZ65cXxUEEcGwd7E8i7g6qmvLDGqZ5JWg
. Merci! (C'était ici quand l'auteur du défi distribuait des prix.)