微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

OR-Tools:0-1 klapsack,对物品来源有限制

如何解决OR-Tools:0-1 klapsack,对物品来源有限制

我正在尝试进行 0-1 背包优化,并限制物品来源。我以 ortools 网站 (ortool example) 上的示例为例,并尝试添加一个约束,使其只能从背包中的每个所有者那里挑选一件物品。

我有一个带有相关权重 (data['weights'])、值 (data['values']) 和源 (data['owns']) 的项目列表。我想找到放入背包的最佳物品组合,因为每个来源只能放入一件物品。

我不知道如何编写约束条件。

如果您查看下面的代码并有 1 个背包,那么最佳解决方案应该是最多从所有者 0 取一件物品,从所有者 1 取一件,从所有者 2 取一件,这遵循重量约束和物品的唯一性挑选(重量低于 100)。

这是我使用的代码(取自ortool多背包示例):

from ortools.linear_solver import pywraplp


def create_data_model():
    """Create the data for the example."""
    data = {}
    data['weights'] = [48,30,42,36,48,24,36]
    data['values'] = [10,25,50,35,15,40,45,10,20,25]
    data['owns'] = [1,1,2,0]
    data['owners'] = list(range(3))
    data['items'] = list(range(len(data['weights'])))
    data['num_items'] = len(data['weights'])
    data['bins'] = []
    data['bin_capacity'] = 100
    return data

def main():
    data = create_data_model()

    # Create the mip solver with the SCIP backend.
    solver = pywraplp.solver.CreateSolver('SCIP')

    # Variables
    # x[i,j] = 1 if item i is packed in bin j.
    x = {}
    for i in data['items']:
        for j in data['bins']:
            x[(i,j)] = solver.Intvar(0,'x_%i_%i' % (i,j))

    # y[i,j] = 1 if item i from owner j in bin.
    y = {}
    for i in data['owns']:
        for j in data['owners']:
            y[(i,'y_%i_%i' % (i,j))

    # Constraints
    # Each item can be in at most one bin.
    for i in data['items']:
        solver.Add(sum(x[i,j] for j in data['bins']) <= 1)
    # Each item can be at from one owner.
    # for i in data['items']:
    #     solver.Add(sum(y[i,j] for j in data['owners']) <= 1)
    # The amount packed in each bin cannot exceed its capacity.
    for j in data['bins']:
        solver.Add(
            sum(x[(i,j)] * data['weights'][i]
                for i in data['items']) <= data['bin_capacity'])

    # Objective
    objective = solver.Objective()

    for i in data['items']:
        for j in data['bins']:
            objective.SetCoefficient(x[(i,j)],data['values'][i])
    objective.Setmaximization()

    status = solver.solve()

    if status == pywraplp.solver.OPTIMAL:
        print('Total packed value:',objective.Value())
        total_weight = 0
        for j in data['bins']:
            bin_weight = 0
            bin_value = 0
            print('Bin ',j,'\n')
            for i in data['items']:
                if x[i,j].solution_value() > 0:
                    print('Item',i,'- weight:',data['weights'][i],' value:',data['values'][i])
                    bin_weight += data['weights'][i]
                    bin_value += data['values'][i]
            print('Packed bin weight:',bin_weight)
            print('Packed bin value:',bin_value)
            print()
            total_weight += bin_weight
        print('Total packed weight:',total_weight)
    else:
        print('The problem does not have an optimal solution.')


if __name__ == '__main__':
    main()

解决方法

首先感谢提供答案的@sascha!

我附在代码下方(我使用了 2 个垃圾箱,3 个不同的所有者):

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from ortools.linear_solver import pywraplp


def create_data_model():
    """Create the data for the example."""
    data = {}
    weights = [48,30,42,36,48,24,36]
    values = [10,25,50,35,15,40,45,10,20,25]
    owns = [0,1,2,2]
    # owns = [0 for _ in range(len(weights))]
    data['weights'] = weights
    data['values'] = values
    data['owners'] = [0,2]
    data['owns'] = owns
    data['items'] = list(range(len(weights)))
    data['num_items'] = len(weights)
    data['bins'] = list(range(2))
    data['bin_capacities'] = [150,100]
    return data

def main():
    data = create_data_model()

    # Create the mip solver with the SCIP backend.
    solver = pywraplp.Solver.CreateSolver('SCIP')

    # Variables
    # x[i,j] = 1 if item i is packed in bin j.
    x = {}
    for i in data['items']:
        for j in data['bins']:
            x[(i,j)] = solver.IntVar(0,'x_%i_%i' % (i,j))

    # Constraints
    # Each item can be in at most one bin.
    for i in data['items']:
        solver.Add(sum(x[i,j] for j in data['bins']) <= 1)

    # Each item can be at from one owner.
    for o in data['owners']:
        for j in data['bins']:
            owner = []
            for i in data['items']:
                if data['owns'][i] == o:
                    owner.append(x[i,j])
            solver.Add(sum(owner) <= 1)

    # The amount packed in each bin cannot exceed its capacity.
    for j in data['bins']:
        solver.Add(
            sum(x[(i,j)] * data['weights'][i]
                for i in data['items']) <= data['bin_capacities'][j])

    # Objective
    objective = solver.Objective()

    for i in data['items']:
        for j in data['bins']:
            objective.SetCoefficient(x[(i,j)],data['values'][i])
    objective.SetMaximization()

    status = solver.Solve()

    if status == pywraplp.Solver.OPTIMAL:
        print('Total packed value:',objective.Value())
        total_weight = 0
        for j in data['bins']:
            bin_weight = 0
            bin_value = 0
            print('Bin ',j,'\n')
            for i in data['items']:
                if x[i,j].solution_value() > 0:
                    print('Item',i,'- weight:',data['weights'][i],' value:',data['values'][i],' owner:',data['owns'][i])
                    bin_weight += data['weights'][i]
                    bin_value += data['values'][i]
            print('Packed bin weight:',bin_weight)
            print('Packed bin value:',bin_value)
            print()
            total_weight += bin_weight
        print('Total packed weight:',total_weight)
    else:
        print('The problem does not have an optimal solution.')


if __name__ == '__main__':
    main()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。