假设我有一个M
元素数组,所有数字,负数或正数或零。
有人建议使用算法从数组中选择N
元素,这样这些N
元素的总和是可能的最小正数吗?
以此数组为例:
-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200
现在我必须选择任何5个元素,使得它们的和是可能的最小正数。
答案 0 :(得分:6)
i = 1, ..., M
:
a_i
成为候选人列表中的i
号码x_i
表示i
号码是否包含在N
个所选号码然后你想解决以下整数编程问题。
minimize: sum(a_i * x_i)
with respect to: x_i
subject to:
(1) sum(a_i * x_i) >= 0
(2) sum(x_i) = N
(3) x_i in {0, 1}
您可以将“开箱即用”的整数程序求解器应用于此问题,以找到最佳解决方案或具有可控精度的次优解决方案。
答案 1 :(得分:0)
我认为Kadane’s Algorithm可以做到这一点,虽然它是最大总和但我已经实现它以找到最小总和,但现在无法找到代码。
答案 2 :(得分:0)
如果你想找到最好的解决方案,你可以简单地使用蛮力即。尝试所有可能的fiwe数字组合。
像这样非常快速和肮脏的算法:
public List<Integer> findLeastPositivSum(List<Integer> numbers) {
List<Integer> result;
Integer resultSum;
List<Integer> subresult, subresult2, subresult3, subresult4, subresult5;
for (int i = 0; i < numbers.size() - 4; i++) {
subresult = new ArrayList<Integer>();
subresult.add(numbers.get(i));
for (int j = i + 1; j < numbers.size() - 3; j++) {
subresult2 = new ArrayList<Integer>(subresult);
subresult2.add(j);
for (int k = j + 1; k < numbers.size() - 2; k++) {
subresult3 = new ArrayList<Integer>(subresult2);
subresult3.add(k);
for (int l = k + 1; l < numbers.size() - 1; l++) {
subresult4 = new ArrayList<Integer>(subresult3);
subresult4.add(k);
for (int m = l + 1; m < numbers.size(); m++) {
subresult5 = new ArrayList<Integer>(subresult4);
subresult5.add(k);
Integer subresultSum = sum(subresult5);
if (subresultSum > 0) {
if (result == null || resultSum > subresultSum) {
result = subresult;
}
}
}
}
}
}
}
return result;
}
public Integer sum(List<Integer> list) {
Integer result = 0;
for (Integer integer : list) {
result += integer;
}
return result;
}
这是一个非常快速和肮脏的算法,它可以做得更优雅。我可以提供清洁算法,例如使用递归。
它还可以进一步优化。例如。您可以从输入列表中删除类似的数字作为第一步。
答案 3 :(得分:0)
让初始数组已经短路了,或者我认为即使它没有短路也能正常工作。
N - >;阵列长度
M - &gt;元素要求。
R [] - &gt;答
TEMP [] - &gt;用于计算
minSum - &gt; minSum
A [] - &gt;初始输入
以上所有变量均为全局定义
int find(int A[],int start,int left)
{
if(left=0)
{
//sum elements in TEMP[] and save it as curSum
if(curSum<minSum)
{
minSum=curSum;
//assign elements from TEMP[] to R[] (i.e. our answer)
}
}
for(i=start;i<=(N-left);i++)
{
if(left==M)
curSum=0;
TEMP[left-1]=A[i];
find(A[],i+1,left-1);
}
}
//匆匆忙忙,所以可能会出现一些错误..
ideone上的工作解决方案: http://ideone.com/YN8PeW
答案 4 :(得分:0)
这是Haskell中的次优化,(与我的许多想法一样)可能会进一步优化。它是这样的:
请注意,对于数组为负数(在升序排序的情况下)或正数(在降序排序的情况下)的数组部分,步骤3可以立即完成而无需计算。
输出:
*Main> least 5 "desc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
(10,[-1000,600,300,100,10])
(0.02 secs, 1106836 bytes)
*Main> least 5 "asc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
(50,[300,100,-200,-100,-50])
(0.02 secs, 1097492 bytes)
*Main> main -- 10000 random numbers ranging from -100000 to 100000
(1,[-106,4,-40,74,69])
(1.77 secs, 108964888 bytes)
代码:
import Data.Map (fromList, insert, (!))
import Data.List (minimumBy,tails,sort)
import Control.Monad.Random hiding (fromList)
array = [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
least n rev arr = comb (fromList listStart) [fst (last listStart) + 1..m]
where
m = length arr
r = if rev == "asc" then False else True
sorted = (if r then reverse else id) (sort arr)
listStart = if null lStart
then [(n,(sum $ take n sorted,take n sorted))]
else lStart
lStart = zip [n..]
. takeWhile (all (if r then (>0) else (<0)) . snd)
. foldr (\a b -> let c = take n (drop a sorted) in (sum c,c) : b) []
$ [0..]
s = fromList (zip [1..] sorted)
comb list [] = list ! m
comb list (i:is)
| fst (list ! (i-1)) == 1 = list ! (i-1)
| otherwise = comb updatedMap is
where updatedMap = insert i bestCandidate list
bestCandidate = comb' (list!(i - 1)) [i - 1,i - 2..n] where
comb' best [] = best
comb' best (j:js)
| fst best == 1 = best
| otherwise =
let s' = map (\x -> (sum x,x))
. (take n . map (take (n - 1)) . tails . cycle)
$ snd (list!j)
t = s!i
candidate = minimumBy compare' (map (add t) s')
in comb' (minimumBy compare' [candidate,best]) js
add x y@(a,b) = (x + a,x:b)
compare' a@(a',_) b@(b',_)
| a' < 1 = if b' < 1 then compare (abs a') (abs b') else GT
| otherwise = if b' < 1 then LT else compare a' b'
rnd :: (RandomGen g) => Rand g Int
rnd = getRandomR (-100000,100000)
main = do
values <- evalRandIO (sequence (replicate (10000) rnd))
putStrLn (show $ least 5 "desc" values)
答案 5 :(得分:-2)
假设:M是原始数组
Pesudocode
S = sort(M);
R = [];
sum = 0;
for(i=0, i < length(S); i++){
sum = sum + S[i];
if(sum < 1){
R.push(S[i]);
}else{
return R;
}
}