检查来自多个数组的数字是否相加为给定的数字
Check if numbers from multiple arrays sum up to given numbers
我试图做这个问题:
给定三个整数: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困难的,所以在多项式时间内找到解决方案的希望不大,但是在伪多项式时间中存在一个解决方案,这使得这个问题相当容易(在复杂问题的世界中)。
该算法的工作原理如下:
- 从包含元组
<0,0,0>
的集合(例如集合)开始。 -
对于每个
纸箱
<a',b',c'>
:遍历集合中<a,b,c>
的所有元组并将<a+a',b+b',c+c'>
添加到集合中,确保不添加重复项。不要添加一个或多个元素超过相应目标值的元组。 - 如果给定集合在算法后包含目标值,则打印"yes",否则打印"no"。
-
可选但强烈建议下限消除:您还可以执行前瞻,例如消除所有永远不会再达到给定目标的值(假设您最多可以添加
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),目标值为 ta、tb 和 tc。
示例 1(两个给定测试用例的高级
):输入
100 100 100
3
10 10 40
10 30 10
10 60 50
集合以 {<0,0,0>}
开头,每次迭代后我们得到:
-
{<0,0,0>}
; -
{<0,0,0>,<10,10,40>}
; -
{<0,0,0>,<10,10,40>,<10,30,10>,<20,40,50>}
; 和 -
{<0,0,0>,<10,10,40>,<10,30,10>,<20,40,50>,<10,60,50>,<10,60,50>,<20,70,90>,<30,100,100>}
,因此失败。
使用欠界消除:
-
{<0,0,0>}
,下限<100-30,100-100,100-100>=<70,0,0>
因此消除了<0,0,0>
。 - 因此
{}
打印"否"。
例 2
输入
100 100 100
5
40 70 30
30 10 40
20 20 50
10 50 90
40 10 20
使用下限消除:
-
{<0,0,0>}
下限:<-40,-60,-130>
这样可以。 -
{<0,0,0>,<40,70,30>}
下限:<0,10,-100>
(消除<0,0,0>
因为第二次冲突)。 -
{<40,70,30>,<70,80,70>}
下限:<30,20,-60>
(不消除)。 -
{<40,70,30>,<70,80,70>,<60,90,80>,<90,100,120>}
下限:<50,40,-10>
(消除<40,70,30>
)上限消除<90,100,120>
。 -
{<70,80,70>,<60,90,80>,<80,130,160>,<70,140,170>}
下限:<60,90,80>
(消除<70,80,70>
)上限消除<80,130,160>
和<70,140,170>
。 -
{<60,90,80>,<100,100,100>}
下限:<100,100,100>
(消除<60,90,80>
)。 - 因此
{<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
结论:尽管最坏情况的行为可能很难,但第二个示例表明,在某些情况下可以有效地解决问题。
- 用于检查数字是否有数字或可被该数字的值整除的程序
- 如何使用递归检查数字是否有重复数字?
- 查找数字是否为 2 的幂的时间复杂度
- 将 C 函数转换为 C++ 以检查数字是否有效
- 检查数字是否为素数的算法
- 在C/C++中检查数字是否为整数(不带scanf/gets/etc)
- 如何以更有效的方式检查一个数字是否是素数?
- C++显示两个区间之间的数字的程序检查一个数字是否可以表示为两个素数的总和
- 如何检查字段中输入的数字是否重复
- 查看数字是否包含在未排序的双数字间隔内的最有效方法?
- 检查数字是否已在数组中的程序
- 编写一个函数,用递归函数检查数字是否是正方形
- 使用模量来找出数字是否可以除去不起作用的变量
- 查找数字是否为素数 c++
- 如何测试某些数字是否沿区间均匀分布?
- 这是确定两个数字是否具有相同奇偶校验的正确方法
- 如何检查 stdin 中的数字是否小于给定类型的数字限制
- 更好的算法来检查一个数字是否既不是素数也不是单个素数的幂
- 如何在不使用数学的情况下知道一个数字是否是回文
- 验证每个数字是否在特定条件下