Heim > Fragen und Antworten > Hauptteil
需求:公司每天下午会抽取4名员工,广州2名,上海2名
注意:员工若当天请假了,需要重新抽取1名员工出来
期待:公平的算法,保证每个员工值班次数在每一轮都近乎相同,并且值班间隔天数也差不多
附上自己的程序:
<?php
/**
* 排班算法
*
* @param array $date 日期范围
* @param int $dayDutys 排班人数
* @param string $city 城市
* @param boolean $isRound 是否循环轮次排班
* @return false|array
*/
function schedule(array $date, $dayDutys = 4, $city = null, $isRound = false)
{
// 值班数据 @todo 有一个值班表了,这边临时用数组代替
$dutys = array();
// 所有员工 @todo 有一个员工表了,这边临时用数组代替
$employees = array(
array('account' => 'a', 'city' => '上海'),
array('account' => 'b', 'city' => '广州'),
array('account' => 'c', 'city' => '上海'),
array('account' => 'd', 'city' => '上海'),
array('account' => 'e', 'city' => '上海'),
array('account' => 'f', 'city' => '上海'),
array('account' => 'g', 'city' => '广州'),
array('account' => 'h', 'city' => '上海'),
array('account' => 'i', 'city' => '广州'),
array('account' => 'j', 'city' => '广州'),
array('account' => 'k', 'city' => '广州'),
array('account' => 'l', 'city' => '上海')
);
// 打乱数组
shuffle($employees);
$gzNum = 0;
$shNum = 0;
$num = 0;
$today = 0;
foreach ($employees as $employee) {
// 无办公地点,过滤
if (!$employee['city']) {
continue;
}
// 超过最大日期,跳出循环
$nowDate = clone($date[0]);
if ($nowDate->modify($today . ' day') > $date[1]) {
break;
}
// 达到当天值班人数峰值,计数清零
if ($num % $dayDutys == 0) {
$gzNum = 0;
$shNum = 0;
}
// 达到当天办公地点值班人数峰值,过滤
if ((($gzNum == $dayDutys / 2 && $employee['city'] == '广州') || ($shNum == $dayDutys / 2 && $employee['city'] == '上海')) && $dayDutys >= 2) {
continue;
}
// 当日已排班,过滤
if ($dutys['account'] == $employee['account'] && $dutys['date'] == array($nowDate, $nowDate)) {
continue;
}
// 本轮未轮完、当月已排班,过滤
if (!$isRound && $dutys['account'] == $employee['account'] && $dutys['date'] == array(new DateTime(date('Y-m-01')), new DateTime(date('Y-m-01') . '1 month'))) {
continue;
}
// 新增值班员工记录
$dutys[] = $employee;
$num ++;
$num % $dayDutys ? $today : $today ++;
$employee['city'] == '广州' ? $gzNum ++ : $shNum ++;
}
// 本轮已轮完,进入下一轮
if ($num % $dayDutys != 0) {
$this->schedule($date, $dayDutys, $city, true);
}
if (!$num) {
return false;
}
return $dutys;
}
希望大神们给予优化或分享,感谢!