检查来自多个阵列的数字是否总和为给定数字

时间:2015-01-09 04:54:56

标签: c++ arrays algorithm knapsack-problem

我试图做这个问题:

  

给出三个整数:GA,GB和GC(代表苹果,橘子,   和香蕉分别)& N行各包含三个整数:   A,B和C,代表苹果,橘子和苹果的数量   香蕉分别在那种食物中。

     

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

     

示例测试用例

     

IN

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

OUT

     

没有

     

IN

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

OUT

     

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

我认为这有点是背包问题的变化,可以以更好的复杂性来解决(至少比O(2 ^ N)[我当前的复杂性]更好; P)。那么,什么是更好的算法来解决这个问题,而且,请参阅我在PasteBin的当前代码(我没有将代码放在stackoverflow上因为它有缺陷,而且,我相信我会有用它开始从头开始...)

3 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:1)

与此question相同的情况。

此问题是来自Facebook Hackercup资格回合的第二个问题,当前正在进行中(它将于1月12日12月1日UTC结束)。

在这里问一些关于积极编程竞赛问题的解决方案并不公平。

答案 2 :(得分:0)

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

该算法的工作原理如下:

  1. 从包含元组<0,0,0>
  2. 的集合(例如集合)开始
  3. 对于每个 carton <a',b',c'>:迭代集合中的所有元组<a,b,c>并将<a+a',b+b',c+c'>添加到集合中,确保未添加重复项。不要添加一个或多个元素超过相应目标值的元组。
  4. 如果给定的集合包含算法后的目标值,请打印“是”,否则“否”
  5. 可选但强烈建议 下限消除:您还可以执行前瞻,例如消除所有永远不会到达给定目标的值(比如说)你最多可以添加20个苹果,然后可以减少所有小于80个苹果的值。

      

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

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

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

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

    INPUT

    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>}因此失败。
    5. 使用 underbound-elimination

      1. {<0,0,0>},下限<100-30,100-100,100-100>=<70,0,0>因此消除了<0,0,0>
      2. {}因此打印“no”
      3. 示例2

        INPUT

        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>}因此“是”
        8. Haskell计划

          我已经实现了一个(不是那么高效,但概念证明)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
          
            

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