Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在多个列中找到和K最接近的N个数?_Python_Algorithm_Optimization_Knapsack Problem_Subset Sum - Fatal编程技术网

Python 如何在多个列中找到和K最接近的N个数?

Python 如何在多个列中找到和K最接近的N个数?,python,algorithm,optimization,knapsack-problem,subset-sum,Python,Algorithm,Optimization,Knapsack Problem,Subset Sum,我试图解决一个优化问题,其中包括寻找,子集和问题的最优解,但是,我们需要找到一个解决方案,其中每列的和最接近每列的唯一数字。另一个限制是,它应该是表中只有45行的总和 我已经尝试过使用Bruteforce,但它只会耗尽系统资源。从我对这个问题的理解来看,这是背包问题的一个子集,叫做子集和问题,但我想在多个列上做这件事 为了更好地说明这个问题 Label | Weight | Parameter 1 | Parameter 2 | Parameter 3 Item1 | 12 |

我试图解决一个优化问题,其中包括寻找,子集和问题的最优解,但是,我们需要找到一个解决方案,其中每列的和最接近每列的唯一数字。另一个限制是,它应该是表中只有45行的总和

我已经尝试过使用Bruteforce,但它只会耗尽系统资源。从我对这个问题的理解来看,这是背包问题的一个子集,叫做子集和问题,但我想在多个列上做这件事

为了更好地说明这个问题

Label | Weight | Parameter 1 | Parameter 2 | Parameter 3
Item1 |   12   |     13      |    91       |      24
Item2 |   76   |     12      |    10       |      14
Item3 |   43   |     11      |    34       |      35
Item4 |   23   |     16      |    11       |      10
Item5 |   23   |     40      |    14       |      12
Item6 |   83   |     70      |    11       |      40
Item7 |   22   |     11      |    41       |      20

我只想找到3行, 参数1之和最接近30
参数2之和最接近于60 参数3之和最接近70

请注意,这是一个带有示例值的示例表

这是一个家庭作业问题,我已经花了很多时间试图解决它。我知道这是一个优化问题,主要是背包问题的边缘问题,我应该用动态规划来解决它,但我不知道如何在多个约束而不是一个约束条件下解决它。我已经研究过多维背包,但不知道怎么做


一个Jupyter笔记本解释如何做会有很大的帮助

你说的是背包问题,但有几个特点:

  • 你不想找到一个精确的和,但最接近的结果的值
  • 问题是多方面的
  • 这个数字不一定是正数
  • 你没有提供距离
我认为最好的办法是枚举size
K
的子集,并选择最接近的和。这是蛮力,但动态规划可能有助于输出子集并计算总和

正如评论中指出的,您首先必须定义
最接近的
的含义。也就是说,定义一个距离。例如,欧几里德距离非常常见:

def d(p1, p2, p3):
    return p1*p1 + p2*p2 + p3*p3
让我们从文件中提取数据,更准确地说,是最后三个值(参数1、2、3)和行的索引:

DATA = """Label | Weight | Parameter 1 | Parameter 2 | Parameter 3
Item1 |   12   |     13      |    91       |      24
Item2 |   76   |     12      |    10       |      14
Item3 |   43   |     11      |    34       |      35
Item4 |   23   |     16      |    11       |      10
Item5 |   23   |     40      |    14       |      12
Item6 |   83   |     70      |    11       |      40
Item7 |   22   |     11      |    41       |      20"""

import io
import csv

f = io.StringIO(DATA)
reader = csv.reader(f, delimiter='|')
next(reader) # skip the header

L = [tuple([int(v) for v in row[-3:]] + [i]) for i, row in enumerate(reader)]
# [(13, 91, 24, 0), (12, 10, 14, 1), (11, 34, 35, 2), (16, 11, 10, 3), (40, 14, 12, 4), (70, 11, 40, 5), (11, 41, 20, 6)]
现在,设置行数
K
和目标
T
(三元组)

这是动态规划,因此我们需要存储中间结果
list\u by\u triplet\u by_k
是嵌套dict的列表:

  • dict
    的索引是使用的行数(我们对
    K
    感兴趣,但需要计算其他值)
  • 外部dict的键是“参数1”的和
  • 第一个嵌套dict的键是“参数2”的和
  • 第二个嵌套dict的键是“参数3”的和
  • 该值是已使用行的列表
(我没有使用四维数组,因为它会非常稀疏。)

一个小技巧:我用目标初始化
list\u by\u triplet\u by_k
。如果有0行,则为-T

list_by_triplet_by_k = [{} for _ in range(N)]
list_by_triplet_by_k[0] = {-T[0]: {-T[1]: {-T[2]: [(-T[0], -T[1], -T[2], "target")]}}}
让我们构建子集。基本上,我们使用动态规划构建了一个由
K+1
树组成的森林:

best = None
ret = []
for a, b, c, i in L:
    for k in range(0, K):
        list_by_triplet = list_by_triplet_by_k[k]
        for u in list_by_triplet.keys():
            for v in list_by_triplet[u].keys():
                for w in list_by_triplet[u][v]:
                    if (a, b, c, i) not in list_by_triplet[u][v][w]: # 0/1
                        list_by_triplet_by_k[k+1].setdefault(a+u, {}).setdefault(b+v, {})[c+w] = list_by_triplet[u][v][w] + [(a, b, c, i)]

    # compute the best match on the fly at the end (not a very useful optimization, but why not?):
    list_by_triplet = list_by_triplet_by_k[K-1]
    for u in list_by_triplet.keys():
        for v in list_by_triplet[u].keys():
            for w in list_by_triplet[u][v]:
                if (a, b, c, i) not in list_by_triplet[u][v][w]: # 0/1
                    cur = d(u+a, v+b, w+c)
                    if best is None or cur < best:
                        best = cur
                        ret = list_by_triplet[u][v][w] + [(a, b, c, i)]
备注:

  • 请参阅以获取信息,但我认为它在任何假设距离下都不起作用
  • 有可能通过一些额外的假设来修剪可能性之树

我会考虑把其中一个标签转换成“算法”来产生额外的兴趣。您需要确定一个标准来衡量一个解决方案有多好,以扩展上一条注释:当三行的Param1之和最接近30,但Param2之和不太接近60,以及另外三行的Param2之和正好相反时,您需要定义什么是最好的。哪一个被认为是最好的?你需要一个需要最小化的表达式。例如
Min(abs(sum(Param1)-30)+abs(sum(Param2)-60)+abs(sum(Param3)-70))
,或者可能
Min(sqr(sum(Param1)-30)+sqr(sum(Param2)-60)+sqr(sum(Param3)-70))
,或者其他的东西。
best = None
ret = []
for a, b, c, i in L:
    for k in range(0, K):
        list_by_triplet = list_by_triplet_by_k[k]
        for u in list_by_triplet.keys():
            for v in list_by_triplet[u].keys():
                for w in list_by_triplet[u][v]:
                    if (a, b, c, i) not in list_by_triplet[u][v][w]: # 0/1
                        list_by_triplet_by_k[k+1].setdefault(a+u, {}).setdefault(b+v, {})[c+w] = list_by_triplet[u][v][w] + [(a, b, c, i)]

    # compute the best match on the fly at the end (not a very useful optimization, but why not?):
    list_by_triplet = list_by_triplet_by_k[K-1]
    for u in list_by_triplet.keys():
        for v in list_by_triplet[u].keys():
            for w in list_by_triplet[u][v]:
                if (a, b, c, i) not in list_by_triplet[u][v][w]: # 0/1
                    cur = d(u+a, v+b, w+c)
                    if best is None or cur < best:
                        best = cur
                        ret = list_by_triplet[u][v][w] + [(a, b, c, i)]
print (best, ret)
# 227 [(-30, -60, -70, 'target'), (12, 10, 14, 1), (11, 34, 35, 2), (16, 11, 10, 3)]