首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何为n个人找到最优的汽车数量?

如何为n个人找到最优的汽车数量?
EN

Stack Overflow用户
提问于 2017-12-22 15:27:04
回答 2查看 2.8K关注 0票数 5

有一套车

代码语言:javascript
运行
复制
{
 3: 1
 4: 1.4
 8: 2.2
}

其中关键是汽车容量,而价值是一个价格系数。

对于很多人来说,我们应该找到一套汽车,价格系数的总和应该尽可能低。例如,对7个人来说,使用一辆容量为8的汽车是合理的,而对9人来说,有一辆8顶的车是可以的。还有一顶3帽。汽车。

形成最优汽车集合的算法是什么?在实际使用中,容量和系数可能不同,因此不依赖于这里提供的数据是很重要的。谢谢!

UPD.这里是一组没有效率因素的汽车代码构建集/希望有可能的汽车变体不估计3

代码语言:javascript
运行
复制
let carSet = {},
    peopleFree = 123456,
    cars =
        [
            {capacity: 3, coefficient: 1},
            {capacity: 4, coefficient: 1.4},
            {capacity: 3, coefficient: 2.2},
        ],
    minCapacity = 0,
    maxCapacity = 0;

_.forEach(cars, (car) => {
    if (car['capacity'] >= maxCapacity) {   //find max capacity
        maxCapacity = car['capacity'];
    }

    if (car['capacity'] <= maxCapacity) {   //find min capacity
        minCapacity = car['capacity'];
    }

    carSet[car['capacity']] = 0;            //create available set of capacities
});

_.forEach(cars, (car) => {

    if (peopleFree <= 0)    //all people are assigned. stopping here
        return;

    if (peopleFree <= minCapacity) {    //if people quantity left are equal to the min car, we assign them
        carSet[minCapacity] += 1;
        peopleFree = 0;
        return;
    }

    let currentCapacityCars = Math.floor(peopleFree / car['capacity']);

    peopleFree = peopleFree % car['capacity'];
    carSet[car['capacity']] = currentCapacityCars;

    if (peopleFree && car['capacity'] == minCapacity) {
        carSet[minCapacity] += 1;
    }
});
return carSet;
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-12-22 22:08:10

您可以使用动态编程技术:

对于给定数量的人,看看一个人的最佳解决方案是否会产生一个空座位。如果是这样的话,这种配置也是对另外一个人最好的配置。

如果不是的话,选择一辆车,让尽可能多的人坐在车里,看看剩下的人有什么最好的解决方案。将最佳解决方案的总价与所选汽车的总价结合起来。对所有类型的汽车重复这一步,并将收益率最低的车拿出来。

还有另一种可能的优化:当创建长系列(为越来越多的人分配)时,一种模式开始一次又一次地重复出现。所以当人数很大的时候,我们可以把结果用在少量的人身上,在模式中同样的“抵消”,然后再加上汽车的数量,也就是随后两个模式块之间的恒定差。我的印象是,当座位数目达到最不常见的倍数时,就会有重复的模式。我们应该采取这一模式的第二块,因为第一个是扭曲的事实,我们不能填补汽车时,我们只有少数人(1或2.)。这种情况不会重演。以3、4和8个座位的汽车为例。LCM是24。有一个有保证的模式,从24人开始重复:在48人,72人,...etc上重复。(它可能会更频繁地重复,但至少它用大小=LCM的块重复)

您可以用自顶向下或自下而上的方法实现DP算法。我在这里以自下而上的方式实现了它,首先计算一个人、两个人的最佳解决方案...etc,直到达到所需的人数为止,始终保持以前的所有结果,这样就不需要计算两次了:

代码语言:javascript
运行
复制
function minimize(cars, people) {
    // Convert cars object into array of objects to facilitate rest of code
    cars = Object.entries(cars)
            .map(([seats, price]) => ({ seats: +seats, price }));
    // Calculate Least Common Multiple of the number of seats:
    const chunk = lcm(...cars.map( ({seats}) => seats ));
    // Create array that will have the DP best result for an increasing
    // number of people (index in the array).
    const memo = [{
        carCounts: Array(cars.length).fill(0),
        price: 0,
        freeSeats: 0
    }];
    // Use DP technique to find best solution for more and more people,
    //   but stop when we have found all results for the repeating pattern.
    for (let i = 1, until = Math.min(chunk*2, people); i <= until; i++) {
        if (memo[i-1].freeSeats) { 
            // Use same configuration as there is still a seat available
            memo[i] = Object.assign({}, memo[i-1]);
            memo[i].freeSeats--;
        } else {
            // Choose a car, place as many as possible people in it,
            //    and see what the best solution is for the remaining people.
            // Then see which car choice gives best result.
            const best = cars.reduce( (best, car, seq) => {
                const other = memo[Math.max(0, i - car.seats)],
                    price = car.price + other.price;
                return price < best.price ? { price, car, other, seq } : best;
            }, { price: Infinity } );
            memo[i] = {
                carCounts: best.other.carCounts.slice(),
                price: best.price,
                freeSeats: best.other.freeSeats + Math.max(0, best.car.seats - i)
            };
            memo[i].carCounts[best.seq]++;
        }
    }
    let result;
    if (people > 2 * chunk) { // Use the fact that there is a repeating pattern
        const times = Math.floor(people / chunk) - 1;
        // Take the solution from the second chunk and add the difference in counts
        //   when one more chunk of people are added, multiplied by the number of chunks:
        result = memo[chunk + people % chunk].carCounts.map( (count, seq) =>
            count + times * (memo[2*chunk].carCounts[seq] - memo[chunk].carCounts[seq])
        );
    } else {
         result = memo[people].carCounts;
    }
    // Format result in Object key/value pairs:
    return Object.assign(...result
                            .map( (count, seq) => ({ [cars[seq].seats]: count })));
}

function lcm(a, b, ...args) {
    return b === undefined ? a : lcm(a * b / gcd(a, b), ...args);
}

function gcd(a, b, ...args) {
    if (b === undefined) return a;
    while (a) {
        [b, a] = [a, b % a];
    }
    return gcd(b, ...args);
}

// I/O management
function processInput() {
    let cars;
    try {
        cars = JSON.parse(inpCars.value);
    } catch(e) {
        preOut.textContent = 'Invalid JSON';
        return;
    }
    const result = minimize(cars, +inpPeople.value);
    preOut.textContent = JSON.stringify(result);
}

inpPeople.oninput = inpCars.oninput = processInput;
processInput(); 
代码语言:javascript
运行
复制
Car definition (enter as JSON):
<input id="inpCars" value='{ "3": 1, "4": 1.4, "8": 2.2 }' style="width:100%"><p>
People: <input id="inpPeople" type="number" value="13" min="0" style="width:6em"><p>
Optimal Car Assignment (lowest price):
<pre id="preOut"></pre>

时间复杂度

没有重复的模式优化,这在O(人*汽车)时间内运行。当这种优化包括在内,它运行在O(座位)*汽车,变得独立于人数。

票数 4
EN

Stack Overflow用户

发布于 2017-12-22 16:12:04

实际上,您的问题只是背包问题。你只需要考虑负重/能力。这样做,您的最小化问题将成为一个最大化的问题。获得最优解的最佳方法是使用动态规划,您可以在这里找到一个例子:https://www.geeksforgeeks.org/knapsack-problem/

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47943833

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档