有两个长度为N的整数序列A[]和B[],两者都是未排序的。
要求:通过交换A[]和B[]之间的元素(可以随机交换,但不能交换相同索引处的元素),使得{A[]中所有元素的总和}与{B[]中所有元素的总和}之差最小。
PS:实际上,这是我遇到的一道面试题。
非常感谢。
有两个长度为N的整数序列A[]和B[],两者都是未排序的。
要求:通过交换A[]和B[]之间的元素(可以随机交换,但不能交换相同索引处的元素),使得{A[]中所有元素的总和}与{B[]中所有元素的总和}之差最小。
PS:实际上,这是我遇到的一道面试题。
非常感谢。
这将是NP难问题!我相信你可以从子集和 进行规约。
根据BlueRaja/polygene的评论,我将尝试提供来自子集和的完整规约。
这是一个规约:
子集和问题:给定整数x1,x2,...,xn,是否存在一些非空子集其总和为零?
我们的问题:给定大小为k的两个整数数组,假设我们可以在数组中移动整数并将两个数组视为一个数组,找到两个数组之和的最小可能差。
假设我们有一个多项式时间算法解决了我们的问题。
现在假设你有整数T = {x1,x2,...,xn}(multiset)
令Si = x1 + x2 + ... + xn + xi。
令 Ti = {x1, x2, ..., xi-1, xi+1, ..., xn } ( = T - xi)
定义
Ai = 使用 Ti 形成的数组
Bi = [Si, 0, ..., 0] (即一个元素是 Si,其余为零)。
让 mi = 我们的问题在数组 Ai 和 Bi 中找到的最小差异
(我们运行我们的问题 n 次)。
声明:当且仅当存在某个 i,使得 mi = 0 时,T 的一些非空子集总和为零。
证明:(wlog)假设 x1 + x2 + .. + xk = 0
那么
A = [xk+1, ..., xn, 0, ...0]
B = [x2, x3, ..., xk, S1, 0, ..0]
给出最小差值 m1 的公式为 |x2 + .. + xk + (x1 + ... + xn) + x1 - (xk+1 + .. + xn)| = |2(x1+ x2 + .. xk)| = 0。
同样,可以证明它的逆命题。
实际上,这也可以更容易地从 Partition 推导出来:只需创建一个全零数组即可。
希望我没有犯任何错误。
试着贪心一点。鉴于信息有限,我不确定还能提供什么其他的建议。
我不确定这是否能确保最小可能的距离,但我脑海中首先想到的是类似于这样的东西:
int diff=0;
for (int i = 0; i<len; i++){
int x = a[i] - b[i];
if (abs(diff - x) > abs(diff + x)){
swap(a,b,i);
diff-=x;
}else{
diff+=x;
}
}
这个问题是NP-完全问题。
我们可以将划分问题简化为此问题的决策版本,即给定两个相同大小的整数数组,确定是否可以交换项目使得和相等。
划分问题的输入:整数集合S,大小为N
为了将此输入转换为我们问题的输入,我们定义A为S中所有项目的数组,B为大小相同的数组,对于所有i,B[i]=0。该转换在输入大小上是线性的。
很明显,如果有一个由S划分成2个子集的方案使得它们的和相等,则我们应用于A和B的算法返回true。