C# 如何找到集合中的哪些数字与另一个给定的数字相加?

C# 如何找到集合中的哪些数字与另一个给定的数字相加?,c#,algorithm,np-complete,np-hard,C#,Algorithm,Np Complete,Np Hard,我在使用会计系统时似乎遇到了一个问题 我有一套交易记录,但它们的金额不等于会计部门认为应该支付的金额。他们并不是在质疑数学,只是包括了交易:p 是否有一种算法可以帮助我确定集合中哪些交易不应包括在内,以便总和与给定金额匹配 Given Set: 2 4 5 7 Given Sum Amount: 13 Result Set: 2 4 7 编辑: 集合中的事务少于100个。有没有人有一个C#的例子,因为在这个问题上没有 老兄,我应该拿到一个CS学位。这是一个NP完全的。除了小

我在使用会计系统时似乎遇到了一个问题

我有一套交易记录,但它们的金额不等于会计部门认为应该支付的金额。他们并不是在质疑数学,只是包括了交易:p

是否有一种算法可以帮助我确定集合中哪些交易不应包括在内,以便总和与给定金额匹配

Given Set:  
2  
4  
5  
7

Given Sum Amount:
13

Result Set:
2
4
7
编辑: 集合中的事务少于100个。有没有人有一个C#的例子,因为在这个问题上没有

老兄,我应该拿到一个CS学位。

这是一个NP完全的。除了小的输入集之外,你不可能用任何东西来精确地解决它。对于任何规模合适的问题集来说,它都是宇宙中解决问题的一生之一


也就是说,有遗传算法背包解算器。

这是一个版本的。它是NP完全的,所以你不会得到一个好的一般答案。您的交易集有多大?是像你展示的那样是5,还是更像500?

这就是问题所在,这是。但这并不意味着没有找到子集和的算法。

正如上述成员所说,这就是子集和问题(或背包问题)。 然而,说它不能有效地完成并不十分准确。这是可以做到的,只是不能 在多项式时间内。使用动态规划的解决方案实际上非常简单 和递归(以及伪多项式时间)

给定整数[a_1,…,a_n]和数字T

定义数组S[i,k]以表示两个数组之间是否存在元素子集 a_1。。。a_i等于k。(这是一个二进制矩阵)

然后,我们可以如下定义递归关系:

S[i,k]=S[i-1,k]或S[i-1,k-aj]

换句话说,这意味着我们要么使用元素a_i,要么不使用元素a_i。 答案将位于S[n,T]

构建矩阵S的工作量是多少? S有n*T个元素。要计算每个元素, 我们必须做一(1)项工作。所以整个运行 时间是O(n*T)

现在,我已经证明了p=NP,如下所示 似乎是一个多项式时间算法。但是,记住 我们用二进制来度量输入大小,所以T=2^p p

我不认为有人会说,当 正确实施是不合理的。事实上,对许多人来说 合理的问题大小,它将表现出色

另外,有一些启发式方法可以解决这个问题,但我是
不是这方面的专家。

好的。很多人都给出了这个问题的名字,并提到它是多么的NP难。总的来说,他们是正确的。但是,您需要解决一个非常具体的案例。首先要问的问题是,你是否认为你的100笔交易接近正确的交易。你有一些总数(“你的”总数)。他们有一些总数。(“实际”总数)。因此,您的一些交易是虚假的。如果你怀疑那里只有一些伪造的交易,那么这也没那么糟糕。例如,让我们考虑只有一个伪造交易的情况。在这种情况下,我们只需要检查100个不同的数字。如果有两个伪造的trans,那么你会看到100*99的支票,在4个伪造的trans中,事情会变得疯狂,几乎有100000000步。不过,如果你所做的只是添加一些int,那就不太可怕了


另一个可能的快捷方式是检查数据的性质(顺便问一下,是否可以发布100个“数字”和预期的总和?)。你的总数比实际总数多多少?是否有任何值如此之大,以至于消除它们会使您的总和突然低于实际总和?如果是这样的话,你知道这些值不可能是假的。例如,在您的示例中,7是绝对必需的

是的,这是可能的。我不确定这篇文章是否仍然开放。但您可能希望执行Excel解算器加载项。张贴所有数字,在相邻单元格上显示1。然后输入所需的输出编号。。然后,所有使用的数字将保留其相邻的“1”,而未使用的数字将变为“0”。然后做一个过滤公式,只列出那些旁边有“1”的

这里也有人向服务员提出了同样的问题:这里有很多潜在的解决方案:正如其他人所说,这是不可能做到的。但是,如果您能够找到一种方法,根据特定于数据的内容来减少搜索空间,您可能会做得更好。但我们都没有足够的信息来帮助这件事……而且即使假设你被允许这样做,也很难提供给我们。布赖恩,我想没有人说这件事做不到,只是说这件事很难(但我想我知道你的意思)@erich事实上,想出一个能找到答案的算法并不难。这可能需要很长时间。你几乎可以说这个解决方案实现起来很简单。@tim:我的意思是“难”有点像双关语,不是指找到算法的难度,而是指找到解决方案。NPC-NP难-你明白我的意思了。+1提供了比其他人更精确的答案。子集和问题是背包问题的一个特例,但这就是背包问题。他不仅仅是问子集是否存在,而是问子集到底是什么。我的理解是子集和是一个精确匹配,而更广义的背包是找到一个最大值。谢谢。昨天我在想如何减少回家路上的交通费用。例如,要使用的集合可以减少为一组交易,其金额小于原始集合总额与预期总额之间的差额。然后在缩减集中查找其总和与该差值匹配的事务。
        bool bBreak = false;
        int iEnd = 13;
        ArrayList ar1 = new ArrayList();
        ar1.Add(2);
        ar1.Add(4);
        ar1.Add(5);
        ar1.Add(7);

        String s1 = " ";
        foreach (int i in ar1)
        {
            if (i == iEnd)
            {
                s1 = "Result = " + i;
                bBreak = true;
            }
            if (bBreak) break;
            ArrayList ar2 = new ArrayList();
            ar2.AddRange(ar1);
            ar2.Remove(i);
            foreach (int j in ar2)
            {
                if ((i + j) == iEnd)
                {
                    s1 = "Results = " + i + ", " + j;
                    bBreak = true;
                }

                if (bBreak) break;
                ArrayList ar3 = new ArrayList();
                ar3.AddRange(ar2);
                ar3.Remove(j);
                foreach (int k in ar3)
                {
                    if (bBreak) break;
                    if ((i + j + k) == iEnd)
                    {
                        s1 = "Results = " + i + ", " + j + ", " + k;
                        bBreak = true;
                    }
                }
            }
        }
        Console.WriteLine(s1);