WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

PHP Задачка: распределить поинты между пользователями

Условия задачи:

Есть такой список очков у пользователей (список отсортирован).

    $list = [
	  'ХОТАБЫЧ'    => 600,
	  'ZaHaria'    => 592,
	  'Arken'      => 568,
	  'FERZ'       => 500,
	  'КАМПУЧИТА'  => 460,
	  'CatAndOr'   => 452,
	  'МРАК'       => 450,
	  'ShuricANik' => 450,
	  '!kostolom!' => 407,
	  'ЛИГА ТЕНЕЙ' => 400,
	  'БАЛАСТ'     => 400,
	  'ogirchuk'   => 347,
	  'Хельга'     => 315,
	  'Banan_tyan' => 313,
	  'ВАЛАДИУС'   => 312,
	  'ХАНС'       => 311,
	  'IzoLenta'   => 208,
	  'Kugacu'     => 77,
	]

Есть еще 1838 «свободных» очков. Их нужно распределить так, чтобы максимально выровнять по очкам всех пользователей.

т.е. нужно получить в результате такой массив:

Array
(
  [ХОТАБЫЧ]    => 600
  [ZaHaria]    => 592
  [Arken]      => 568
  [FERZ]       => 500
  [КАМПУЧИТА]  => 482
  [CatAndOr]   => 482
  [МРАК]       => 482
  [ShuricANik] => 482
  [!kostolom!] => 482
  [ЛИГА ТЕНЕЙ] => 482
  [БАЛАСТ]     => 481
  [ogirchuk]   => 481
  [Хельга]     => 481
  [Banan_tyan] => 481
  [ВАЛАДИУС]   => 481
  [ХАНС]       => 481
  [IzoLenta]   => 481
  [Kugacu]     => 481
)

Код должен уметь работать с большим количеством распределяемых очков и большим массивом пользователей.

Решение:

Самое простое решение выглядит так, подойдет если изначально дается не большой массив в который нужно распределить не большое кол-во очков (автор Campusboy):

function normilize_points( & $list, $points ){

	for ( $i = 1; $i <= $points; $i ++ ) {
		$index = array_search( min( $list ), $list );
		++ $list[ $index ];
	}
}

Решение посложнее, которое может работать с большим объемом данных (автор Kama):

function normilize_points( & $list, $points ){

	$count = count( $list );

	// уровняем

	for( $index = 0; $index < $count; $index++ ){

		$sub_array = array_slice( $list, $index );
		$root_num = reset( $sub_array );
		$sub_array = array_map( fn( $val ) => $root_num - $val, $sub_array );

		$sum = array_sum( $sub_array );

		if( $sum <= $points ){
			break;
		}
	}

	// распределим оставшееся равномерно

	$left_points = $points - $sum;

	$fill_evenly__fn = static function( $to_add ) use ( & $sub_array, & $left_points ){

		foreach( $sub_array as & $num ){
			$num += $to_add;
			$left_points -= $to_add;

			if( ! $left_points ){
				break;
			}
		}
	};

	// пачками
	if( $left_points ){
		$to_add = (int) ( $left_points / count( $sub_array ) );

		$fill_evenly__fn( $to_add );
	}

	// по 1
	if( $left_points ){
		$fill_evenly__fn( 1 );
	}

	// заполняем результат
	foreach( $sub_array as $key => $add ){
		$list[ $key ] += $add;
	}
}
Комментариев нет
    Войти