您将获得一组整数,您的任务如下:将它们分成2个子集,其总和相等,以使这些总和最大。你被允许不使用所有给定的整数,这没关系。如果它不可能,请以某种方式报告错误。
我的方法相当简单:在每一步,我们选择一个项目,将其标记为已访问,更新当前总和并递归选择另一个项目。最后,尝试跳过当前元素。
它适用于更简单的测试用例,但它失败了:
T = 1
N = 25
要素:5 27 24 12 12 2 15 25 32 21 37 29 20 9 24 35 26 8 31 5 25 21 28 3 5
可以按如下方式运行:
1 25 5 27 24 12 12 2 15 25 32 21 37 29 20 9 24 35 26 8 31 5 25 21 28 3 5
我希望sum等于239,但算法无法找到这样的解决方案。
我最终得到了以下代码:
#include <iostream>
#include <unordered_set>
using namespace std;
unordered_set<uint64_t> visited;
const int max_N = 50;
int data[max_N];
int p1[max_N];
int p2[max_N];
int out1[max_N];
int out2[max_N];
int n1 = 0;
int n2 = 0;
int o1 = 0;
int o2 = 0;
int N = 0;
void max_sum(int16_t &sum_out, int16_t sum1 = 0, int16_t sum2 = 0, int idx = 0) {
if (idx < 0 || idx > N) return;
if (sum1 == sum2 && sum1 > sum_out) {
sum_out = sum1;
o1 = n1;
o2 = n2;
for(int i = 0; i < n1; ++i) {
out1[i] = p1[i];
}
for (int i = 0; i < n2; ++i) {
out2[i] = p2[i];
}
}
if (idx == N) return;
uint64_t key = (static_cast<uint64_t>(sum1) << 48) | (static_cast<uint64_t>(sum2) << 32) | idx;
if (visited.find(key) != visited.end()) return;
visited.insert(key);
p1[n1] = data[idx];
++n1;
max_sum(sum_out, sum1 + data[idx], sum2, idx + 1);
--n1;
p2[n2] = data[idx];
++n2;
max_sum(sum_out, sum1, sum2 + data[idx], idx + 1);
--n2;
max_sum(sum_out, sum1, sum2, idx + 1);
}
int main() {
int T = 0;
cin >> T;
for (int t = 1; t <= T; ++t) {
int16_t sum_out;
cin >> N;
for(int i = 0; i < N; ++i) {
cin >> data[i];
}
n1 = 0;
n2 = 0;
o1 = 0;
o2 = 0;
max_sum(sum_out);
int res = 0;
int res2 = 0;
for (int i = 0; i < o1; ++i) res += out1[i];
for (int i = 0; i < o2; ++i) res2 += out2[i];
if (res != res2) cerr << "ERROR: " << "res1 = " << res << "; res2 = " << res2 << '\n';
cout << "#" << t << " " << res << '\n';
visited.clear();
}
}
我有以下问题:
答案 0 :(得分:2)
我唯一能看到的问题是你没有将sum_out设置为0。
当我尝试运行该程序时,它似乎可以正常运行您的测试用例。
见问题3的答案
您目前正在跟踪您是否看到了value for first subset
,value for second subset
,amount through array
的每一种选择。
相反,如果您跟踪值之间的差异,则复杂性会显着降低。
特别是,你可以使用动态编程来存储一个数组A [diff],对于差值的每个值,它存储-1(表示差异不可达),或者当差异存在时,则为subset1的最大值subset1和subset2之间完全等于diff。
然后,您可以迭代输入中的条目,并根据将每个元素分配给subset1 / subset2 /或根本不更新数组来更新数组。 (注意,在计算此更新时,您需要创建数组的新副本。)
在这种形式中没有使用unordered_set,因为你可以简单地使用直的C数组。在subset1和subset2之间也没有区别,所以你只能保持正差异。
from collections import defaultdict
data=map(int,"5 27 24 12 12 2 15 25 32 21 37 29 20 9 24 35 26 8 31 5 25 21 28 3 5".split())
A=defaultdict(int) # Map from difference to best value of subset sum 1
A[0] = 0 # We start with a difference of 0
for a in data:
A2 = defaultdict(int)
def add(s1,s2):
if s1>s2:
s1,s2=s2,s1
d = s2-s1
if d in A2:
A2[d] = max( A2[d], s1 )
else:
A2[d] = s1
for diff,sum1 in A.items():
sum2 = sum1 + diff
add(sum1,sum2)
add(sum1+a,sum2)
add(sum1,sum2+a)
A = A2
print A[0]
这打印239作为答案。
为简单起见,我没有打扰使用线性数组而不是字典的优化。