[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: небольшой алгоритм
alexfbm
Привет всем, кто может придумать алгоритм? Задача следующая:

Случайным образом выбираем, кому дать бутылку пива: Пете, Васе или Ивану.
Но вероятность получения бутылки пива у каждого человека разная - у Пети 10%, и Васи 60%, а у Ивана 30% (человек может быть от двух до десяти).

Как выбрать счастливчика? В болшинстве случаев пивко получать будет Вася, но иногда радость выпадет и для Ивана с Петей.
Если можно то напишите и код ;)




function get_winner($a)
{
......
return $winner;
}

$a = array("Petya" => 10, "Vasya" => 60, "Ivan" => 30);
$name = get_winner($a); // "Vasya"
$name = get_winner($a); // "Vasya"
$name = get_winner($a); // "Ivan"
$name = get_winner($a); // "Vasya"
$name = get_winner($a); // "Petya"


$a = array("Petya" => 50, "Vasya" => 50);
$name = get_winner($a); // "Petya"
$name = get_winner($a); // "Petya"
$name = get_winner($a); // "Vasya"

// и так далее






Спустя 4 минуты, 19 секунд (25.08.2011 - 12:07) linker написал(а):
Как-то так
$pivo = rand(1, 100);
if ($pivo <= 10)
echo 'Дать Пете';
else
if
($pivo > 10 && $pivo <= 70)
echo 'Дать Васе';
else
if
($pivo > 70)
echo 'Дать Ивану';
но правда слишком утрировано.

Спустя 3 минуты, 56 секунд (25.08.2011 - 12:11) alexfbm написал(а):
linker, спасибо конечно, до такого варианта я и сам додумался, но в данном примере не катит smile.gif Кол-во людей разное и на входе я не знаю цифр 10 и 70.

Обновил свой пост, посмотри что на входе имеется.

Спустя 54 минуты, 4 секунды (25.08.2011 - 13:05) linker написал(а):
А всё просто, если за 100% взять значение 100, то у Пети 10% - будет значение 10, у Васи 60% - 60 (Петя + 60 = 70), у Ивана 30% - 30 (Вася + 30 = 100). А дальше думай.

Спустя 49 минут, 18 секунд (25.08.2011 - 13:55) alexfbm написал(а):
Походу написал функцию, по крайней мере сколько не тестил, все работает правильно.


function get_winner($a)
{
$winner = false;

// proverjaem, verni li vhodnie dannie (summa procentov dolzhna bitj 100%)

$check_percent = 0;
foreach ($a as $v) {
$check_percent += $v;
}

if ($check_percent == 100)
{

// esli neskolko ljudej imeejut odin i tot zhe procent, to sortiruem imenno etih ljudej randomom.
uasort ($a, function ($a, $b){
if ($a == $b) {
$vals = array(-1, 1);
return $vals[array_rand($vals)];
}
elseif ($a > $b) {
return 1;
}
return 0;
});

//sortiruem v porjadke ubivanija (po procentu)
arsort($a);

// vichisljaem pobeditelja
$rand_nr = rand(1,100);

$a_original = $a;

$i = 1;
$prev = 0;
foreach ($a as $k=>$v)
{
$next = next($a_original);

if ($next > 0)
{
if ($i == 1){
if ($rand_nr <= $v) {
$winner = $k;
break;
}
}

else {
if ($rand_nr >= $prev && $rand_nr <= (100 - $next)) {
$winner = $k;
break;
}
}

$prev = $v;
}
else {
if ($rand_nr >= (100 - $v)) {
$winner = $k;
break;
}
}

$i++;
}
}


return $winner;
}


$a = array("Petya" => 10, "Vasya" => 60, "Ivan" => 30);
//$a = array("Petya" => 20, "Vasya" => 80);
//$a = array("Petya" => 50, "Vasya" => 50);
//$a = array("Petya" => 10, "Vasya" => 20, "Ivan" => 30, "Sasha"=>20, "Oleg" =>20);
//$a = array("Petya" => 100, "Vasya" => 0);
//$a = array("Petya" => 100);


$name = get_winner($a);

Спустя 29 минут, 30 секунд (25.08.2011 - 14:24) linker написал(а):
А у меня примерно так получилось
function winner($mens)
{
$lastMax = 0;
$val = rand(1, 100);
foreach($mens as $name => $percent)
{
$count = $percent * 100/100;
$max = $count + $lastMax;
if ($val >= $lastMax && $val <= $max)
return $name;
}
}


echo winner(array('Петя' => 10, 'Вася' => 60, 'Иван' => 30));

Спустя 13 минут (25.08.2011 - 14:37) alexfbm написал(а):
linker

не рабоает - функция часто возвращает пустоту. Провертьте с моими примерами.

Спустя 2 минуты (25.08.2011 - 14:39) linker написал(а):
У меня пока ещё ни разу пустоты не выдало.

Спустя 4 минуты (25.08.2011 - 14:43) alexfbm написал(а):
Цитата (linker @ 25.08.2011 - 11:39)
У меня пока ещё ни разу пустоты не выдало.

F5 понажимайте в браузере.. у меня уже после третьего раза выдало пустоту.

Спустя 32 секунды (25.08.2011 - 14:44) linker написал(а):
Да, забыл один момент
$lastMax = $max;
т.е. должно быть так
function winner($mens)
{
$lastMax = 0;
$val = rand(1, 100);
foreach($mens as $name => $percent)
{
$count = $percent * 100/100;
$max = $count + $lastMax;
if ($val >= $lastMax && $val <= $max)
return $name;
$lastMax = $max;
}
}


echo winner(array('Петя' => 10, 'Вася' => 60, 'Иван' => 30));

Спустя 2 минуты, 4 секунды (25.08.2011 - 14:46) linker написал(а):
Если в цикле
$res = array();
for($i = 0; $i < 100; ++ $i)
{
$name = winner(array('Петя' => 10, 'Вася' => 60, 'Иван' => 30));
if (isset($res[$name]))
++
$res[$name];
else
$res[$name] = 1;
}
print_r($res);
то вроде примерно честное распределение получается.

Спустя 7 минут, 19 секунд (25.08.2011 - 14:53) alexfbm написал(а):
Да, все верно теперь у вас работает. Я так же проверил и свой пример в цикле, результаты одинаковые, тоже честно распределяет. Но у вас реализация более элегантная)
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2025 Invision Power Services, Inc.