Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 子集合加总问题_C#_Sql Server_Algorithm_.net 3.5 - Fatal编程技术网

C# 子集合加总问题

C# 子集合加总问题,c#,sql-server,algorithm,.net-3.5,C#,Sql Server,Algorithm,.net 3.5,我的计数有问题,这是问题的继续。我不是一个真正的数学人,所以我真的很难解决这个被建议作为解决方案的子集和问题 我有4个ArrayList,其中保存着数据:alId、alTransaction、alNumber、alPrice 类型|交易|编号|价格 8 |购买| 95.00000000 | 305.00000000 8 |买入| 126.00000000 | 305.00000000 8 |买入| 93.00000000 | 306.00000000 8 |转出| 221.00000000 |

我的计数有问题,这是问题的继续。我不是一个真正的数学人,所以我真的很难解决这个被建议作为解决方案的
子集和问题

我有4个
ArrayList
,其中保存着数据:alId、alTransaction、alNumber、alPrice

类型|交易|编号|价格
8 |购买| 95.00000000 | 305.00000000
8 |买入| 126.00000000 | 305.00000000
8 |买入| 93.00000000 | 306.00000000
8 |转出| 221.00000000 | 305.00000000
8 |转入| 221.00000000 | 305.00000000
8 |出售| 93.00000000 | 360.00000000
8 |出售| 95.00000000 | 360.00000000
8 |出售| 126.00000000 | 360.00000000
8 |购买| 276.00000000 | 380.00000000

最后,我将尝试获取留给客户的剩余内容,并将剩余内容放入3个数组列表中:
-ALNEWHOWMOUNT(对应于alNumber),
-alNewPrice(对应于alPrice),
-alNewInID(对应于alID)

但它只有在满足某些条件的情况下才能起作用,而在其他情况下则会失败


编辑:由于你们中的一些人对我的波兰语变量名感到惊讶(并且盲目),为了简单易懂,我将它们全部翻译成了英语。希望这能帮助我得到一些帮助:-)

你应该怎么做取决于一些重要的事情:你有多少个数字,它们有多大?另外,据我所知,您的数据可以更改(添加/删除数字等),对吗?。您需要多久进行一次这些查询

我将提出两种解决方案。我建议你使用第二种,因为我认为它更适合你的需要,而且更容易理解

解决方案1-动态规划

如果我们可以求和i,则设S[i]=true,否则设为false。

S[0] = true // we can always make sum 0: just don't choose any number
S[i] = false for all i != 0
for each number i in your input
    for s = MaxSum downto i
        if ( S[s - i] == true )
            S[s] = true; // if we can make the sum s - i, we can also make the sum s by adding i to the sum s - i.
要获得构成总和的实际数字,您应该保留另一个向量
p[i]=用于构成总和i的最后一个数字。您将在上面的
条件中相应地更新此项

这个算法的时间复杂度是
O(numberOfNumbers*maxSumOfAllNumbers)
,这非常糟糕,尤其是当数据发生变化时,您必须重新运行这个算法。即使是一次跑步,速度也很慢,只要你的数字很大,而且你可以拥有很多。事实上,“很多”是误导。如果您有100个数字,每个数字可以大到10000,那么每次数据更改时,您将执行大约100*10000=1000000个操作

这是一个很好的解决方案,但在实践中并没有真正的用处,或者至少在你的情况下我认为没有

他对我建议的方法有些怀疑:

   class Program
      {
        static void Main(string[] args)
        {
            List<int> testList = new List<int>();

            for (int i = 0; i < 1000; ++i)
            {
                testList.Add(1);
            }

            Console.WriteLine(SubsetSum.Find(testList, 1000));

            foreach (int index in SubsetSum.GetLastResult(1000))
            {
                Console.WriteLine(index);
            }
        }
    }

    static class SubsetSum
    {
        private static Dictionary<int, bool> memo;
        private static Dictionary<int, KeyValuePair<int, int>> prev;

        static SubsetSum()
        {
            memo = new Dictionary<int, bool>();
            prev = new Dictionary<int, KeyValuePair<int, int>>();
        }

        public static bool Find(List<int> inputArray, int sum)
        {
            memo.Clear();
            prev.Clear();

            memo[0] = true;
            prev[0] = new KeyValuePair<int,int>(-1, 0);

            for (int i = 0; i < inputArray.Count; ++i)
            {
                int num = inputArray[i];
                for (int s = sum; s >= num; --s)
                {
                    if (memo.ContainsKey(s - num) && memo[s - num] == true)
                    {
                        memo[s] = true;

                        if (!prev.ContainsKey(s))
                        {
                            prev[s] = new KeyValuePair<int,int>(i, num);
                        }
                    }
                }
            }

            return memo.ContainsKey(sum) && memo[sum];
        }

        public static IEnumerable<int> GetLastResult(int sum)
        {
            while (prev[sum].Key != -1)
            {
                yield return prev[sum].Key;
                sum -= prev[sum].Value;
            }
        }
    }
在算法结束时,列表
usedNums
将给出总和为
S
的数字

我认为这个算法应该适合你的需要。它可以很好地处理对数据集的更改,并且适用于高计数。它也不取决于数字有多大,如果你有大的数字,这是非常有用的


如果您有任何问题,请发布。

这是我的算法。它在
O(2^(n/2))
中运行,并在20毫秒内求解
子问题(1000,1000个一组)
。请参阅IVlad帖子末尾的评论

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace SubsetSum
{
    class Program
    {
        static void Main(string[] args)
        {
            var ns = new List<int>();
            for (int i = 0; i < 1000; i++) ns.Add(1);
            var s1 = Stopwatch.StartNew();
            bool result = SubsetSum(ns, 1000);
            s1.Stop();
            Console.WriteLine(result);
            Console.WriteLine(s1.Elapsed);
            Console.Read();
        }

        static bool SubsetSum(ist<int> nums, int targetL)
        {
            var left = new List<int> { 0 };
            var right = new List<int> { 0 };
            foreach (var n in nums)
            {
                if (left.Count < right.Count) left = Insert(n, left);
                else right = Insert(n, right);
            }
            int lefti = 0, righti = right.Count - 1;
            while (lefti < left.Count && righti >= 0)
            {
                int s = left[lefti] + right[righti];
                if (s < target) lefti++;
                else if (s > target) righti--;
                else return true;
            }
            return false;
        }

        static List<int> Insert(int num, List<int> nums)
        {
            var result = new List<int>();
            int lefti = 0, left = nums[0]+num;
            for (var righti = 0; righti < nums.Count; righti++)
            {

                int right = nums[righti];
                while (left < right)
                {
                    result.Add(left);
                    left = nums[++lefti] + num;
                }
                if (right != left) result.Add(right);
            }
            while (lefti < nums.Count) result.Add(nums[lefti++] + num);
            return result;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统诊断;
命名空间子类
{
班级计划
{
静态void Main(字符串[]参数)
{
var ns=新列表();
对于(int i=0;i<1000;i++)ns,添加(1);
var s1=Stopwatch.StartNew();
bool结果=子类(ns,1000);
s1.停止();
控制台写入线(结果);
控制台写入线(s1已过);
Console.Read();
}
静态布尔分区(ist nums,int targetL)
{
var left=新列表{0};
var right=新列表{0};
foreach(以nums为单位的变量n)
{
如果(left.Count=0)
{
int s=左[lefti]+右[righti];
如果(s目标)正确--;
否则返回true;
}
返回false;
}
静态列表插入(int num,List nums)
{
var result=新列表();
int lefti=0,left=nums[0]+num;
对于(var righti=0;righti
下面是一个改进的版本,用于修剪集合:

static bool SubsetSum(List<int> nums, int target)
{
    var remainingSum = nums.Sum();
    var left = new List<int> { 0 };
    var right = new List<int> { 0 };
    foreach (var n in nums)
    {
        if (left.Count == 0 || right.Count == 0) return false;
        remainingSum -= n;
        if (left.Count < right.Count) left = Insert(n, left, target - remainingSum - right.Last(), target);
        else right = Insert(n, right, target - remainingSum - left.Last(), target);
    }
    int lefti = 0, righti = right.Count - 1;
    while (lefti < left.Count && righti >= 0)
    {
        int s = left[lefti] + right[righti];
        if (s < target) lefti++;
        else if (s > target) righti--;
        else return true;
    }
    return false;
}

static List<int> Insert(int num, List<int> nums, int min, int max)
{
    var result = new List<int>();
    int lefti = 0, left = nums[0]+num;
    for (var righti = 0; righti < nums.Count; righti++)
    {

        int right = nums[righti];
        while (left < right)
        {
            if (min <= left && left <= max) result.Add(left);
            left = nums[++lefti] + num;
        }
        if (right != left && min <= right && right <= max) result.Add(right);
    }
    while (lefti < nums.Count)
    {
        left = nums[lefti++] + num;
        if (min <= left && left <= max) result.Add(left);
    } 
    return result;
}
static bool SubsetSum(列出nums,int-target)
{
var remainingSum=nums.Sum();
var left=新列表{0};
var right=新列表{0};
foreach(以nums为单位的变量n)
{
if(left.Count==0 | | right.Count==0)返回false;
剩余总和-=n;
if(left.Count=0)
{
int s=左[lefti]+右[righti];
如果(s目标)正确--;
否则返回true;
}
返回fals
while S != usedSum
    if S > usedSum // our current usedSum is too small
        move a random number from unusedNums to usedNums and update usedSum
    else // our current usedSum is too big
        move a random number from usedNums to unusedNums and update usedSum
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace SubsetSum
{
    class Program
    {
        static void Main(string[] args)
        {
            var ns = new List<int>();
            for (int i = 0; i < 1000; i++) ns.Add(1);
            var s1 = Stopwatch.StartNew();
            bool result = SubsetSum(ns, 1000);
            s1.Stop();
            Console.WriteLine(result);
            Console.WriteLine(s1.Elapsed);
            Console.Read();
        }

        static bool SubsetSum(ist<int> nums, int targetL)
        {
            var left = new List<int> { 0 };
            var right = new List<int> { 0 };
            foreach (var n in nums)
            {
                if (left.Count < right.Count) left = Insert(n, left);
                else right = Insert(n, right);
            }
            int lefti = 0, righti = right.Count - 1;
            while (lefti < left.Count && righti >= 0)
            {
                int s = left[lefti] + right[righti];
                if (s < target) lefti++;
                else if (s > target) righti--;
                else return true;
            }
            return false;
        }

        static List<int> Insert(int num, List<int> nums)
        {
            var result = new List<int>();
            int lefti = 0, left = nums[0]+num;
            for (var righti = 0; righti < nums.Count; righti++)
            {

                int right = nums[righti];
                while (left < right)
                {
                    result.Add(left);
                    left = nums[++lefti] + num;
                }
                if (right != left) result.Add(right);
            }
            while (lefti < nums.Count) result.Add(nums[lefti++] + num);
            return result;
        }
    }
}
static bool SubsetSum(List<int> nums, int target)
{
    var remainingSum = nums.Sum();
    var left = new List<int> { 0 };
    var right = new List<int> { 0 };
    foreach (var n in nums)
    {
        if (left.Count == 0 || right.Count == 0) return false;
        remainingSum -= n;
        if (left.Count < right.Count) left = Insert(n, left, target - remainingSum - right.Last(), target);
        else right = Insert(n, right, target - remainingSum - left.Last(), target);
    }
    int lefti = 0, righti = right.Count - 1;
    while (lefti < left.Count && righti >= 0)
    {
        int s = left[lefti] + right[righti];
        if (s < target) lefti++;
        else if (s > target) righti--;
        else return true;
    }
    return false;
}

static List<int> Insert(int num, List<int> nums, int min, int max)
{
    var result = new List<int>();
    int lefti = 0, left = nums[0]+num;
    for (var righti = 0; righti < nums.Count; righti++)
    {

        int right = nums[righti];
        while (left < right)
        {
            if (min <= left && left <= max) result.Add(left);
            left = nums[++lefti] + num;
        }
        if (right != left && min <= right && right <= max) result.Add(right);
    }
    while (lefti < nums.Count)
    {
        left = nums[lefti++] + num;
        if (min <= left && left <= max) result.Add(left);
    } 
    return result;
}