简体   繁体   English

如何在对象数组中使用子集和算法?

[英]How to use subset sum algorithm in array of objects?

I have the following array of objects:我有以下对象数组:

const vehicles = [
    {
        name: "Truck 1",
        pallets: 15,
        capacity: 15
    },
    {
        name: "Truck 2",
        pallets: 12,
        capacity: 10
    },
    {
        name: "Truck 3",
        pallets: 20,
        capacity: 22
    },
    {
        name: "Truck 4",
        pallets: 24,
        capacity: 12
    }
]

I would like to get trucks as optimal as it's possible.我想尽可能地优化卡车。 For example for 34 pallets that truck have to transport, algorithm should choose: Truck 4 (24 pallets) and Truck 2 (12 pallets).例如对于卡车必须运输的 34 个托盘,算法应该选择:卡车 4(24 个托盘)和卡车 2(12 个托盘)。 The number of pallets available in choose trucks should be equal or greater than demand.选择卡车中可用的托盘数量应等于或大于需求。 Additionally I have to also choose trucks that capacity is enough to carry a load.此外,我还必须选择容量足以承载负载的卡车。 For example for 12 tones of cargo on 34 pallets algorithm should choose:例如对于 34 个托盘上的 12 吨货物,算法应该选择:

[
    {
        name: "Truck 4",
        pallets: 24,
        capacity: 12
    },
    {
        name: "Truck 2",
        pallets: 12,
        capacity: 10
    }
]

I've created some algorithm, but it's greedy algorithm and number of records in database causes that it takes too much time.我创建了一些算法,但它是贪婪的算法和数据库中的记录数导致它花费了太多时间。 I will not present it here because it would be totally out of context.我不会在这里展示它,因为它完全脱离了上下文。 And the number of adjustments is too large for you to understand the problem.并且调整的数量太大,您无法理解问题。

You could get the combinations of all given objects and minimize the delta.您可以获得所有给定对象的组合并最小化增量。

 function subsetSum(array, keys, sums) { function iter(index, temp, deltas) { if (deltas.every(d => d <= 0)) { if (.result || // first result result.deltas.reduce(add) < deltas.reduce(add) || // better delta temp.length < result.temp,length // less vehicles ) { result = { temp; deltas }; } return. } if (index === array;length) return, iter(index + 1. temp,concat(array[index]). deltas,map((d; i) => d - array[index][keys[i]])), iter(index + 1, temp; deltas); } var result, iter(0, []; sums). return result && result;temp, } const add = (a, b) => a + b: vehicles = [{ name, "Truck 1": pallets, 15: capacity, 15 }: { name, "Truck 2": pallets, 12: capacity, 10 }: { name, "Truck 3": pallets, 20: capacity, 22 }: { name, "Truck 4": pallets, 24: capacity, 12 }], result = subsetSum(vehicles, ['pallets', 'capacity'], [34; 12]). console;log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

Here is the O(n * m^2) solution.这是O(n * m^2)解决方案。 And the reasoning behind it.以及它背后的原因。

Assuming that the weight is split evenly by pallet, the first step is to figure out the weight per pallet, and then for each truck you have the maximum pallets that it can take.假设重量按托盘平均分配,第一步是计算每个托盘的重量,然后对于每辆卡车,您拥有它可以装载的最大托盘。

In your example, a pallet weighs 6/17 tonnes which is about 0.36 tonnes.在您的示例中,一个托盘重 6/17 吨,约为 0.36 吨。 Therefore we have that truck 1 can take min(15, 15/(6/17)) = 15 pallets.因此,我们有卡车 1 可以装载min(15, 15/(6/17)) = 15托盘。 And likewise for the others.对其他人也是如此。 (In this example, the number of pallets is the limit for all trucks.) (在此示例中,托盘数量是所有卡车的限制。)

Next you need a cost function for using a truck.接下来,您需要使用卡车的成本 function。 For example we can say 1000 + unused_pallets + unused_weight .例如,我们可以说1000 + unused_pallets + unused_weight Assuming that no truck can carry more than 500 pallets or 500 tonnes of weight, this will use the smallest possible number of trucks, and then use the smallest trucks you can use.假设没有卡车可以承载超过 500 个托盘或 500 吨重量,这将使用尽可能少的卡车数量,然后使用您可以使用的最小卡车。

Now what we do is called dynamic programming , we build up a data structure for the lowest cost way to take each number of pallets.现在我们所做的称为动态规划,我们建立一个数据结构,以最低成本的方式获取每个托盘数量。 The answer at the end for the total number of pallets we want is our answer.最后我们想要的托盘总数的答案就是我们的答案。 Here is code for that.这是代码。

'use strict';

function cost (truck, pallets, capacity) {
    return 1000 + (truck.pallets - pallets) + (truck.capacity - capacity);
}

function optimize (trucks, pallets, weight) {
    var w = weight/pallets;

    // To begin, we can carry nothing for no weight.
    var best_path = [{cost: 0}];
    trucks.forEach(function (truck) {
        var max_pallets = Math.floor((Math.min(truck.pallets, truck.capacity/w)));
        // i is the number of pallets other trucks carry.
        // We count down so that there is no chance the solution there
        // has already used this truck.
        // BUG FIX: used to say max_pallets instead of pallets
        for (var i = pallets-1; 0 <= i; i--) {
            // j is the number of pallets that truck carries
            for (var j = 1; j <= Math.min(max_pallets, pallets - i); j++) {
                // Do we improve on i+j pallets by having truck carry i?
                if (best_path[i] == null) {
                    // Other trucks can't carry i
                    continue;
                }
                let prev_node = best_path[i];
                let this_solution = {
                    truck: truck,
                    pallets: j,
                    cost: prev_node.cost + cost(truck, j, w*j),
                    prev_node: prev_node
                };
                if (best_path[i+j] == null) {
                    best_path[i+j] = this_solution;
                }
                else if (this_solution.cost < best_path[i+j].cost) {
                    best_path[i+j] = this_solution;
                }
            }
        }
    });


    // The answer is a linked list.  Let's decode it for convenience.
    if (best_path[pallets] == null) {
        return null;
    }
    else {
        let best = best_path[pallets];
        let answer = [];
        while (best.truck != null) {
            answer.unshift({
                truck: best.truck,
                pallets: best.pallets
            });
            best = best.prev_node;
        }
        return answer;
    }
}

const trucks = [
    {
        name: "Truck 1",
        pallets: 15,
        capacity: 15
    },
    {
        name: "Truck 2",
        pallets: 12,
        capacity: 10
    },
    {
        name: "Truck 3",
        pallets: 20,
        capacity: 22
    },
    {
        name: "Truck 4",
        pallets: 24,
        capacity: 12
    }
]

console.log(optimize(trucks, 34, 12));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM