Java, $ 806.899
Isto é de um teste de 2501 rodadas. Ainda estou trabalhando para otimizá-lo. Eu escrevi duas aulas, um invólucro e um jogador. O invólucro instancia o player com o número de envelopes (sempre 10000 para a coisa real) e depois chama o método takeQ
com o valor do envelope superior. O jogador então retorna true
se eles pegarem, false
se passarem.
Jogador
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);
}
}
Embrulho
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;
}
}
}
Uma explicação mais detalhada estará disponível em breve, depois que eu terminar as otimizações.
A idéia central é poder estimar a recompensa de jogar um jogo de um determinado conjunto de envelopes. Se o conjunto atual de envelopes for {2,4,5,7,8,9} e o envelope superior for o 5, existem duas possibilidades:
- Pegue o 5 e jogue com {7,8,9}
- Passe o 5 e jogue {2,4,7,8,9}
Se calcularmos a recompensa esperada de {7,8,9} e compará-la com a recompensa esperada de {2,4,7,8,9}, seremos capazes de dizer se tirar 5 vale a pena.
Agora, a pergunta é: dado um conjunto de envelopes como {2,4,7,8,9} qual é o valor esperado? Descobri que o valor esperado parece ser proporcional à quantidade total de dinheiro no conjunto, mas inversamente proporcional à raiz quadrada do número de envelopes em que o dinheiro é dividido. Isso veio "perfeitamente" jogando vários jogos pequenos nos quais todos os envelopes têm valor quase idêntico.
O próximo problema é como determinar o " número efetivo de envelopes". Em todos os casos, o número de envelopes é conhecido exatamente acompanhando o que você viu e fez. Algo como {234.235.236} é definitivamente três envelopes, {231.232.233.234.235} é definitivamente 5, mas {1.2.234.235.236} deve realmente contar como 3 e não 5 envelopes, porque o 1 e o 2 são quase inúteis, e você nunca passaria em um 234. você poderia pegar um 1 ou 2. Mais tarde, tive a ideia de usar a entropia de Shannon para determinar o número efetivo de envelopes.
Eu direcionei meus cálculos para situações em que os valores do envelope são distribuídos uniformemente por algum intervalo, que é o que acontece durante o jogo. Se eu pegar {2,4,7,8,9} e tratar isso como uma distribuição de probabilidade, sua entropia é 1,50242. Então eu faço exp()
para obter 4,49254 como o número efetivo de envelopes.
A recompensa estimada de {2,4,7,8,9} é 30 * 4.4925^-0.5 * 4/3 = 18.87
O número exato é 18.1167
.
Essa não é uma estimativa exata, mas estou realmente orgulhosa de como isso se encaixa nos dados quando os envelopes são distribuídos uniformemente por um intervalo. Não tenho certeza do multiplicador correto (estou usando 4/3 por enquanto), mas aqui está uma tabela de dados excluindo o multiplicador.
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
A regressão linear entre o esperado e o real fornece um valor de R ^ 2 de 0,999994 .
Meu próximo passo para melhorar esta resposta é melhorar a estimativa quando o número de envelopes começar a ficar pequeno, ou seja, quando os envelopes não estiverem aproximadamente uniformemente distribuídos e quando o problema começar a ficar granulado.
Edit: Se isso é considerado digno de bitcoins, acabei de receber um endereço em 1PZ65cXxUEEcGwd7E8i7g6qmvLDGqZ5JWg
. Obrigado! (Foi aqui que o autor do desafio estava distribuindo prêmios.)