这是硬算法问题:
将列表分成两部分(总和),表示它们的总和最接近(大多数)
列表长度为1&lt; = n&lt; = 100并且它们的(数字)权重1 <= w <= 250,在问题中给出。
例如:23 65 134 32 95 123 34
1.sum = 256
2.sum = 250
1.list = 1 2 3 7
2.list = 4 5 6
我有一个算法,但它并不适用于所有输入。
实施: list1 = [],list2 = []
依旧......
答案 0 :(得分:7)
您可以将其重新表述为knapsack problem。
您有一个总重量为M的物品清单,应安装在可容纳最大重量M / 2的垃圾箱中。包装在垃圾箱中的物品应尽可能重,但不要超过垃圾箱。
对于所有权重都是非负数的情况,此问题仅为weakly NP-complete并且具有多项式时间解决方案。
可以在Wikipedia上找到针对此问题的动态编程解决方案的说明。
答案 1 :(得分:4)
问题是NPC,但是有一个伪多项式算法,这是一个2-Partition问题,你可以按照sub set sum问题的伪多项式时间算法来解决这个问题。如果输入大小与输入值多项相关,则可以在多项式时间内完成。
在你的情况下(权重<250),它是多项式(因为权重&lt; = 250 n =&gt; sums&lt; = 250 n ^ 2)。
设Sum =权重之和,我们必须创建二维数组A,然后按列构造A,
A [i,j] =真如果(j == weight [i]或j - weight [i] = weight [k](k在列表中))。
使用此算法创建数组需要O(n ^ 2 * sum / 2)。
最后我们应该找到最有价值的专栏。
以下是一个例子:
项:{0,1,2,3} 权重:{4,7,2,8} =&gt; sum = 21 sum / 2 = 10
items/weights 0| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
---------------------------------------------------------
|0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0
|1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0
|2 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1
|3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1
因为a [10,2] == true,分区是10,11
这是我找到的算法here并进行了一些编辑以解决您的问题:
bool partition( vector< int > C ) {
// compute the total sum
int n = C.size();
int N = 0;
for( int i = 0; i < n; i++ ) N += C[i];
// initialize the table
T[0] = true;
for( int i = 1; i <= N; i++ ) T[i] = false;
// process the numbers one by one
for( int i = 0; i < n; i++ )
for( int j = N - C[i]; j >= 0; j--)
if( T[j] ) T[j + C[i]] = true;
for(int i = N/2;i>=0;i--)
if (T[i])
return i;
return 0;
}
我刚刚返回T [i],这是真的,而不是返回T [N / 2](最大到最小顺序)。
找到给出这个值的路径并不难。
答案 2 :(得分:2)
这个问题至少与NP完全问题subset sum一样困难。你的算法是一个贪婪的算法。这种类型的算法速度快,可以快速生成近似解,但无法找到NP完全问题的精确解。
蛮力方法可能是解决问题的最简单方法,但如果元素太多,它会慢下来。
生成所有分区可以通过考虑从0到2 ^ n的每个整数的二进制表示来完成,其中每个二进制数字确定相应的元素是在左分区还是右分区。
答案 3 :(得分:0)
试图解决我在以下想法中遇到的相同问题,这似乎是一个解决方案,但它在线性时间内起作用。能否提供一个示例来表明它不起作用或解释为什么它不是解决方案?
arr = [20,10,15,6,1,17,3,9,10,2,19] # a list of numbers
g1 = []
g2 = []
for el in reversed(sorted(arr)):
if sum(g1) > sum(g2):
g2.append(el)
else:
g1.append(el)
print(f"{sum(g1)}: {g1}")
print(f"{sum(g2)}: {g2}")
答案 4 :(得分:0)
打字稿代码:
import * as _ from 'lodash'
function partitionArray(numbers: number[]): {
arr1: number[]
arr2: number[]
difference: number
} {
let sortedArr: number[] = _.chain(numbers).without(0).sortBy((x) => x).value().reverse()
let arr1: number[] = []
let arr2: number[] = []
let median = _.sum(sortedArr) / 2
let sum = 0
_.each(sortedArr, (n) => {
let ns = sum + n
if (ns > median) {
arr1.push(n)
} else {
sum += n
arr2.push(n)
}
})
return {
arr1: arr1,
arr2: arr2,
difference: Math.abs(_.sum(arr1) - _.sum(arr2))
}
}