检查来自多个数组的数字是否相加为给定的数字

Check if numbers from multiple arrays sum up to given numbers

本文关键字:数字 是否 数组 检查      更新时间:2023-10-16

我试图做这个问题:

给定三个整数:GA、GB 和 GC(代表苹果、橙子、 和香蕉)和N行,每行由三个整数组成: A、B 和 C,代表苹果、橙子和 香蕉分别在那食物中。

检查是否可以仅使用某些纸箱,以便总计 苹果、橙子和香蕉的总和分别为 GA、Gb 和 GC。为 每个可用的纸箱,我们只能选择购买或不购买。 他不能多次购买某个纸箱,他不能购买 纸箱的分数。

示例测试用例

100 100 100
3
10 10 40
10 30 10
10 60 50

100 100 100
5
40 70 30
30 10 40
20 20 50
10 50 90
40 10 20

是的

对于这个问题,我写了一些代码,但只得到了分段错误和一些错误。另外,我的算法很糟糕。我所做的是找到苹果数组的所有子集,使它们的总和为 GA,然后我检查这些集合中是否有橙子和香蕉要添加到 GB 和 GC 中。但是这个想法非常缓慢,而且很难编码......

我相信这在某种程度上是背包问题的变体,可以以更好的复杂性解决(至少比 O(2^N)[我当前的复杂性]更好);那么,有什么更好的算法来解决这个问题,并且,请参阅我在 PasteBin 上的当前代码(我没有将代码放在堆栈溢出上,因为它有缺陷,而且,我相信我必须从头开始......

分段错误完全是你的问题。

背包是NP完全的,这也是(假设输入中A,B,C总是相同的,并且Ga=A之和的一半)。我认为没有人要求你在这里解决NP完全问题。

显然,您不会检查所有集合,而只检查总和 A <= 100、总和 B <= 100、总和 C <=100 的集合。

与此问题相同的情况。

这个问题是Facebook黑客杯资格赛的第二个问题,目前正在进行中(它将在1月12日UTC时间上午12点结束)。

在这里为活跃的编程竞赛问题寻求解决方案是不公平的。

这是 0-1 背包问题的变体。这个问题是NP困难的,所以在多项式时间内找到解决方案的希望不大,但是在伪多项式时间中存在一个解决方案,这使得这个问题相当容易(在复杂问题的世界中)。

该算法的工作原理如下:

  1. 从包含元组<0,0,0>的集合(例如集合)开始。
  2. 对于每个 纸箱<a',b',c'>:遍历集合中<a,b,c>的所有元组并将<a+a',b+b',c+c'>添加到集合中,确保不添加重复项。不要添加一个或多个元素超过相应目标值的元组。
  3. 如果给定集合在算法后包含目标值,则打印"yes",否则打印"no"。
  4. 可选但强烈建议下限消除:您还可以执行前瞻,例如消除所有永远不会再达到给定目标的值(假设您最多可以添加20个苹果,那么所有小于 80 个苹果的值都可以被消除)。

    概念 1(下限):由于您将元组的值相加,现在如果<a0,a1,a2>有元组并且还剩下<b0,b1,b2>元组,添加这些元组最多会增加一个元组<a0+b0,a1+b1,a2+b2>。现在假设目标是<t0,t1,t2>那么如果q0+a0+b0 < t0(泛化到其他元组元素),您可以安全地消除元组<q0,q1,q2>,因为即使您可以添加最后一个元组,它也永远不会达到所需的值。因此,下限是<t0-a0-b0,t1-a1-b1,t2-a2-b2> 。您可以将其概括为 n 个元组。

因此,首先将所有提供的元组相加(对于第二个实例,这是<140,160,230>),然后从目标中减去它(结果因此:<-40,-60,-130>)。每次迭代,下限都会随着该纸箱的增加而增加,因此在第一次迭代之后,第二个示例的结果是 ( <-40+40,-60+70,-130+30><0,10,-100> )。

然而,时间复杂度为 O(ta^3 tb^3 tc^3),目标值为 tatbtc

示例 1(两个给定测试用例的高级

):

输入

100 100 100
3
10 10 40
10 30 10
10 60 50

集合以 {<0,0,0>} 开头,每次迭代后我们得到:

  1. {<0,0,0>} ;
  2. {<0,0,0>,<10,10,40>} ;
  3. {<0,0,0>,<10,10,40>,<10,30,10>,<20,40,50>} ; 和
  4. {<0,0,0>,<10,10,40>,<10,30,10>,<20,40,50>,<10,60,50>,<10,60,50>,<20,70,90>,<30,100,100>},因此失败。

使用欠界消除

  1. {<0,0,0>},下限<100-30,100-100,100-100>=<70,0,0>因此消除了<0,0,0>
  2. 因此{}打印"否"。

例 2

输入

100 100 100
5
40 70 30
30 10 40
20 20 50
10 50 90
40 10 20

使用下限消除

  1. {<0,0,0>}下限:<-40,-60,-130>这样可以。
  2. {<0,0,0>,<40,70,30>}下限:<0,10,-100>(消除<0,0,0>因为第二次冲突)。
  3. {<40,70,30>,<70,80,70>}下限:<30,20,-60>(不消除)。
  4. {<40,70,30>,<70,80,70>,<60,90,80>,<90,100,120>}下限:<50,40,-10>(消除<40,70,30>)上限消除<90,100,120>
  5. {<70,80,70>,<60,90,80>,<80,130,160>,<70,140,170>}下限:<60,90,80>(消除<70,80,70>)上限消除<80,130,160><70,140,170>
  6. {<60,90,80>,<100,100,100>}下限:<100,100,100>(消除<60,90,80>)。
  7. 因此{<100,100,100>}"是"。

哈斯克尔计划

我已经实现了一个(不是那么高效,但概念证明)Haskell程序,它可以解决任意元组长度:

import qualified Data.Set as Set
tupleSize :: Int
tupleSize = 3
group :: Int -> [a] -> [[a]]
group _ [] = []
group n l = take n l : group n (drop n l)
empty :: Int -> Set.Set [Int]
empty n = Set.fromList [replicate n 0]
solve :: [Int] -> [[Int]] -> Bool
solve t qs = Set.member t $ mix t (lowerBound t qs) qs $ empty $ length t
lowerBound :: [Int] -> [[Int]] -> [Int]
lowerBound = foldl (zipWith (-))
lowerCheck :: [Int] -> [Int] -> Bool
lowerCheck l x = and $ zipWith (<=) l x
targetCheck :: [Int] -> [Int] -> Bool
targetCheck t x = and $ zipWith (>=) t x
takeout :: Int -> [a] -> [a]
takeout _ [] = []
takeout i (h:hs) | i == 0 = hs
                 | otherwise = h : takeout (i-1) hs
mix :: [Int] -> [Int] -> [[Int]] -> Set.Set [Int] -> Set.Set [Int]
mix _ _ [] s = s
mix t l (q:qs) s = mix t (zipWith(+) l q) qs $ Set.filter (lowerCheck l) $ Set.union s $ Set.filter (targetCheck t) $ Set.map (zipWith (+) q) s
reply :: Bool -> String
reply True = "yes"
reply False = "no"
main = interact $ x -> let tuples = group tupleSize $ takeout tupleSize $ map read (words x) in reply $ solve (head tuples) (tail tuples)

您可以使用以下命令编译运行它:

ghc file.hs
./file < input

结论:尽管最坏情况的行为可能很难,但第二个示例表明,在某些情况下可以有效地解决问题。