PHP查找内部数组中的总和的所有组合

时间:2017-08-01 16:10:48

标签: php multidimensional-array

我正在为酒店的可用房间编写PHP脚本。我希望每个组合(即4人)。这是我的阵容。

$room_array = array(
    array(
        "title"         => "1 person room",
        "room_for"      => 1,
        "price"         => 79
    ),
    array(
        "title"         => "2 person room with other",
        "room_for"      => 1,
        "price"         => 69
    ),
    array(
        "title"         => "2 person room alone",
        "room_for"      => 1, 
        "price"         => 89
    ),
    array(
        "title"         => "2 person",
        "room_for"      => 2,
        "price"         => 69
    ),
    array(
        "title"         => "3 person",
        "room_for"      => 3,
        "price"         => 69
    )
);

可能的结果:

  • 4x 1人房
  • 4x 2人房间与其他
  • 3x 1人房+ 1x 2人房及其他
  • 2x 2人房
  • 1x 3人房+ 1x 1人房

等。等

这需要一个递归函数。但是我看到的每个例子都不适用于计算内部数组。我找到的最接近的是这个问题:

Finding potential combinations of numbers for a sum (given a number set to select from)

但我没有得到解决方案......

更新

嗨,谢谢你的所有答案。真的帮助我找到了最佳实践。与此同时,作业发生了一些变化,因此我无法回答自己原来的问题。我的问题解决了。再次感谢您的帮助!

3 个答案:

答案 0 :(得分:0)

如果您需要所有组合,那么您可以使用回溯迭代算法(深度路径)。

总结:

  1. 树的类型:二叉树,因为当被污染的人数=目标时,所有级别都可以包含解决方案

    Binary tree

  2. 算法功能 每当生成一个等级时,你需要增加一个等级,当你改变你的轨迹时,你需要增加一个等级(探索兄弟或者回来)

  3. 解决方案:数组[0..levels-1]值{0(节点未选中),1(节点选中)}

    solution [0] = 1 - >您选择“1人房间”属于解决方案

    解决方案:列表/对象数组,每个对象都包含房间标题数组

    function Backtracking ()
        level:= 1
        solution:= s_initial
        end:= false
        repeat
             generate(level, solution)
             IF solution(level, solution) then
               save_solution
             else if test(level, solution) then
                level:= level+ 1
             else
                while NOT MoreBrothers(level, solution)
                   go_back(level, s)
    
        until level==0
    

    2.1。生成:生成下一个节点

    2.2。解决方案:测试它是否是解决方案

    2.3。批评:如果我们必须继续这条轨道或绑定

    2.4。 MoreBrothers:如果在这个级别有没有检查的节点

    2.5。 Backtrack:探索了这个级别的所有节点

    2.6。保存解决方案:将包含字符串

    的对象添加到解决方案数组中

答案 1 :(得分:0)

declare @table table (id int, section int, secstart datetime, secstop datetime)
insert into @table
values
(101,1,'2010-03-06 02:27:49.000','2010-03-06 02:34:32.000'),
(101,2,'2010-03-06 02:28:25.000','2010-03-06 02:34:32.000'),
(101,3,'2010-03-06 02:29:58.000','2010-03-06 02:34:32.000'),
(102,1,'2008-09-11 02:15:22.000','2008-09-11 02:34:55.000'),
(102,2,'2008-09-11 02:25:32.000','2008-09-11 02:34:55.000')


select
    id
    ,section
    ,DATEDIFF(minute,secstart,secstop) MinuteDifference
from @table

select
    x.id
    ,x.section
    ,DATEDIFF(minute,x.secstart,t.secstart) MinuteDifference
from 
    @table x
left join 
    @table t on 
    t.section = x.section + 1 
    and t.id = x.id

输出看起来像这样:

$room_array = array(
    array(
        "title"         => "1 person room",
        "room_for"      => 1,
        "price"         => 79
    ),
    array(
        "title"         => "2 person room with other",
        "room_for"      => 1,
        "price"         => 69
    ),
    array(
        "title"         => "2 person room alone",
        "room_for"      => 1,
        "price"         => 89
    ),
    array(
        "title"         => "2 person",
        "room_for"      => 2,
        "price"         => 69
    ),
    array(
        "title"         => "3 person",
        "room_for"      => 3,
        "price"         => 69
    )
);

// Gets rooms based on a given number of guests
function get_possible_rooms($num_guests) {
    global $room_array;
    $possible_rooms = [];

    foreach ($room_array as $room) {
        if ($num_guests <= $room['room_for']) {
            $possible_rooms[] = $room['title'];
        }
    }

    return $possible_rooms;
}

// Gets the available room capacities
function get_room_capacities() {
    global $room_array;
    $capacities = [];

    foreach ($room_array as $room) {
        $capacities[] = $room['room_for'];
    }

    return array_unique($capacities);
}

// Gets the different combinations of groups of guests based on the room capacities
function get_guest_assignments($remaining_guests, $parent_id = '', $num_guests, &$result) {
    $room_capacities = get_room_capacities();

    for ($i = 1; $i <= $remaining_guests; ++$i) {
        if (in_array($i, $room_capacities)) {
            $parent_guests = (isset($result[$parent_id])) ? $result[$parent_id] : 0;
            $result[$parent_id . $i] = $parent_guests + $i;

            for ($j = 1; $j <= $remaining_guests - $i; ++$j) {
                // Recursively get the results for children
                get_guest_assignments($j, $parent_id . $i, $num_guests, $result);
            }
        }
    }

    if ($remaining_guests === 1 && $parent_id !== '') {
        // If it reaches the end and it does not fulfill the required number of guests,
        // mark it for removal later
        if ($result[$parent_id] < $num_guests) {
            $result[$parent_id] = null;
        }
    }

    // This is the last recursion
    if ($result[$parent_id . '1'] === $num_guests) {
        // Remove duplicates. 
        // To do this, we need to re-sort the keys (e.g. 21 becomes 12) and call array_unique()
        // I admit this is a bit sloppy implementation.
        $combinations = [];

        foreach ($result as $key => $value) {
            if ($value !== null) {
                $nums = str_split($key);
                sort($nums);
                $combinations[] = implode('', $nums);
            }
        }

        $result = array_unique($combinations);
    }
}

// Gets the rooms for each group of guest
function get_room_assignments($guest_str) {
    $rooms = [];

    for ($i = 0; $i < strlen($guest_str); ++$i) {
        $num_guests = intval(substr($guest_str, $i, 1));
        $rooms[] = get_possible_rooms($num_guests);
    }

    return $rooms;
}

//----------
// RUN
//----------

$guests = 4;
$result = [];

get_guest_assignments($guests, null, $guests, $result);

foreach ($result as $guest_combi) {
    $assignments = get_room_assignments($guest_combi);

    // Printing output
    echo 'Guest Combination ' . $guest_combi . "\n";
    echo json_encode($assignments, JSON_PRETTY_PRINT);
    echo "\n\n";
}

&#34;嘉宾组合13&#34;意味着4位客人将分成1人和3人一组。

输出是每组可能的房间数组。因此在示例中,组1 可以预订1人房间,2人房间与其他,... 3人房间。而 3人组可以预订3人房间。

-

其他说明:

  • 我知道我们讨厌... Guest Combination 13 [ [ "1 person room", "2 person room with other", "2 person room alone", "2 person", "3 person" ], [ "3 person" ] ] ... ,但为了简洁起见这样做。随意修改。
  • 这是一种较短的编码方式,但由于客户组合被用作密钥,因此这种实现方式使调试更容易。

答案 2 :(得分:0)

我在下面的回答会让你在那里。

资源

我从this回答借用了一些代码逻辑。 要引用答案(如果将来删除),请查看以下内容。

  

你可以尝试

echo "<pre>";
$sum = 12 ; //SUM
$array = array(6,1,3,11,2,5,12);
$list = array();
# Extract All Unique Conbinations
extractList($array, $list);
#Filter By SUM = $sum     $list =
array_filter($list,function($var) use ($sum) { return(array_sum($var) == $sum);});
#Return Output
var_dump($list);
     

输出

array
  0 => array
    1 => string '1' (length=1)
    2 => string '2' (length=1)
    3 => string '3' (length=1)
    4 => string '6' (length=1)
  1 => array
    1 => string '1' (length=1)
    2 => string '5' (length=1)
    3 => string '6' (length=1)
  2 => array
    1 => string '1' (length=1)
    2 => string '11' (length=2)
  3 => array
    1 => string '12' (length=2)
     

使用的功能

function extractList($array, &$list, $temp = array()) {
    if(count($temp) > 0 && ! in_array($temp, $list))
        $list[] = $temp;
    for($i = 0; $i < sizeof($array); $i ++) {
        $copy = $array;
        $elem = array_splice($copy, $i, 1);
        if (sizeof($copy) > 0) {
            $add = array_merge($temp, array($elem[0]));
            sort($add);
            extractList($copy, $list, $add);
        } else {
            $add = array_merge($temp, array($elem[0]));
            sort($add);
            if (! in_array($temp, $list)) {
                $list[] = $add;
            }
        }
    }
}

我的回答

以下代码使用上面引用的代码。我更改了array_filter函数的返回功能,以将其映射到您的需求。

您唯一要做的就是更改功能,以便它可以捕获多个相同类型的房间。目前,下面的代码只输出每种类型房间中的1个(根据上面引用的代码)。解决此问题的一种简单方法是将您发送给函数的数组值乘以搜索房间的客人数量,但最多可达到可用房间数量。所以:如果您打算预订4位客人并且您没有剩余单人间且只有1间双人间,那么您的最佳匹配结果必须是2 person room和{{1 }}。我添加了一些简要功能来添加它(它被注释掉了),虽然我还没有测试过。这可能需要一段时间来处理它,所以如果你正在寻找一种更快的方法,你将不得不使用前面评论/答案中已经提到的更好的算法或解决P vs NP

下面的代码还为您提供了切换值3 person room的选项。此值(如果设置为$exact)将仅返回完全等于来宾数的匹配项,如果设置为true,则返回等于的所有匹配项至少是客人人数

false