整数拆分算法

yqydaful 2018-04-28 10:36:16
一个整数,按指定整数列表进行拆分,要满足拆分次数少,尽量按整数列表的顺序拆分。
比如总的整数为50,整数列表是有顺序的,为10,8,7,7,15,13,6,6,3,3,3,4,8,9,10,13,14
可能的结果:50=10+8+7+7+15+3(6次),50=10+8+7+15+10(5次),50=10+8+7+7+6+4+8(7次),等等
要求:一是尽量用列表顺序在前面的数字,二是拆分次数要少。输出最有可能的三种情况
...全文
1346 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
yqydaful 2018-05-01
  • 打赏
  • 举报
回复
引用 14 楼 sp1234 的回复:
其实这个问题看起来并不复杂,你找一个学数学、学统计的人问一下,用过这类计算机工具的人,让他给你讲一下你这个问题的模型。可以考虑按顺序优先加工,先满足第一个活儿最优解,然后再在这个范围内找到满足第二个活儿的最优解..........可以以物料浪费最少和物料不足最少为求解目标。你应该补充几个约束条件,使得你的模型具有实际生产价值。对于规划求解的算法来说,你这里给出你的约束条件太简单了(而不是太多了),反而不容易看到实用性。
谢谢 以专业开发人员为伍 xuzuning ,你们说的是对的,需要找找统计方面的人员来了解下,说不定有更好的建议。因为我现在的想法,还是停留在怎么找算法,或者说用代码来实现。 我现在的基本做法就是,一个物料 一个物料来,使用上面的算法,先确定一个解,然后再确定第二个解。
  • 打赏
  • 举报
回复
怎么说呢?随便举个例子吧,比如说一个百货公司物流配送,有1000种货物,要配送到40个自营百货商场,满足一些约束条件使得配送最经济,同时每一个商场的备货恰好合适,大概就是这样每天做计划的。
  • 打赏
  • 举报
回复
其实这个问题看起来并不复杂,你找一个学数学、学统计的人问一下,用过这类计算机工具的人,让他给你讲一下你这个问题的模型。可以考虑按顺序优先加工,先满足第一个活儿最优解,然后再在这个范围内找到满足第二个活儿的最优解..........可以以物料浪费最少和物料不足最少为求解目标。你应该补充几个约束条件,使得你的模型具有实际生产价值。对于规划求解的算法来说,你这里给出你的约束条件太简单了(而不是太多了),反而不容易看到实用性。
xuzuning 2018-05-01
  • 打赏
  • 举报
回复
设计算法是总是要先知道解的大致范围的,比如一个发散的函数,不管你怎么去做,都是得不到解的 你即没有说每箱能装多少,也没说打算生产多少箱,原料也从定值变成不定值了 考虑到有 目的是省料,那么是否可以认为:如果原料的长度恰好都是 25 的倍数,那么全部生产成 XL-1 就可以了?显然并不妥当 从列表上看,是否 6002 是不能生产出 XL-11 的,而只能生产出 XL-3、XL-12? 如果是这样,那你就把简单问题混淆复杂问题了 你总是强调多少工位,其实这并不是主要矛盾。1个工位和100个工位,并没有本质的区别,因为每个工位的单位时效应该认为是一样的
  • 打赏
  • 举报
回复
许多所谓的“拆分、组合”问题都可以使用运筹学的规划方法来求解,但是规划问题本身更突出首先面向业务来建模,而不是简单地“整数拆分”。你随便上 Excel 论坛就会看到许多会计、统计人员、HR人员、生产管理人眼贴了许多 Excel 表,使用 Excel 在求解规划问题。
  • 打赏
  • 举报
回复
复杂问题应该使用运筹学规划方法,甚至是多目标的规划方法。使用简单穷举的方法是不能快速找到最优解的,因为这个方法连建模(线性或者非线性方程)都没有,所以几乎根本不可能在计算过中找到优化的依据。
yqydaful 2018-05-01
  • 打赏
  • 举报
回复
谢谢上面各位的解答。本身这个需求,可能还需要约束下条件。其实是一个排产的算法。我详细说下要求。 生产任务:有多个周转箱,最好是按照顺序生产。 每一个周转箱,包含多个线束,而一个线束,包含多个线缆(可以是同一物料)。线束中的线缆长度一样。 同时加工线缆的工位,有32个,每一个物料当前线缆长度随机(之前定的是50), 之所以考虑数列中的数字和要等于或接近,指定的数字,目的是省料,不浪费。 周转箱号 线束号 线缆号 物料 长度 BOX001 A-1 XL-1 6001 25 BOX001 A-1 XL-2 6001 25 BOX001 A-1 XL-3 6002 25 BOX001 A-2 XL-4 6001 20 BOX001 A-2 XL-5 6003 20 。。。 BOX002 A-11 XL-11 6001 7 BOX002 A-11 XL-12 6002 12 BOX002 A-13 XL-13 6003 4 BOX002 A-14 XL-14 6004 6 BOX002 A-15 XL-14 6005 15 。。。 即要生产的线束,物料很多。之前说到的整数数列,其实只是一个物料的。 比如要生产的周转箱有20个。现在可用的线缆物料,共有32个工位, 这32个工位的物料,可以是同一物料,也可以是多个物料的组合。 大家给的算法,我也试过。就单个物料来说,我可以优先考虑第一种结果就可以了。因为给出的数列就是按照加工顺序给的。 现在是多个物料,多个加工数列,组合一起。我的想法是,还是要考虑按顺序优先加工,这样可能加工次数,就不能优化了。 希望大家再集思广议,一起帮我想想
threenewbee 2018-04-28
  • 打赏
  • 举报
回复
如果每个数字只用一次,需要修改下判断。 另外尽量取前面的和尽量组合少,两个要求矛盾,你要得到确定的结果,必须舍弃一个。
threenewbee 2018-04-28
  • 打赏
  • 举报
回复
https://ask.csdn.net/questions/687105 和这个思路差不多
u011140974 2018-04-28
  • 打赏
  • 举报
回复
这个用背包算法就可以实现。
threenewbee 2018-04-28
  • 打赏
  • 举报
回复
引用 6 楼 xuzuning 的回复:
用组合去实现是最直接的,但求组合的算法并不保证能按原始位置顺序排列(因为求组合的算法实现太多了),简单点的求组合算法还要求原始数据无重复项 https://ask.csdn.net/questions/687105 的算法是求组合算法的变形,但他利用了二进制数位,这就局限了待处理数据的规模 我的这个算法实际也是求组合算法的变形,利用栈消除递归 如在 default 分支中排除掉预期超限的数据,有可能提高效率,和减小栈的规模。 虽然最终无效组合都被删去了,但每次新增的待处理项的规模还是相当可观的
哈哈,那个问题中lz的程序效率是不高,所以才提问的。要看下面我写的程序。
  • 打赏
  • 举报
回复
上边的,应该把“组合”叫做“排列”了,其实是排列而不是组合。 算法本身很简单,其实只有两句话。简单就意味这你很容易扩展算法。
  • 打赏
  • 举报
回复
en,如果要保持原来给出的数据顺序不变,应该做出约束,可以这样
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var list = new List<int> { 10, 8, 7, 7, 15, 13, 6, 6, 3, 3, 3, 4, 8, 9, 10, 13, 14 };
            var cnt = 0;
            foreach (var r in 组合(list, 50, 0).Take(20))
            {
                Console.Write("第{0}个组合:", ++cnt);
                foreach (var s in r)
                    Console.Write("{0} ", s);
                Console.WriteLine("  {0}次", r.Count());
            }
            Console.WriteLine("...................按任意键结束");
            Console.ReadKey();
        }

        static IEnumerable<IEnumerable<int>> 组合(List<int> arr, int goal, int index)
        {
            for (var i = index; i < arr.Count; ++i)
            {
                if (arr[i] == goal)
                    yield return new int[] { arr[i] };
                else if (arr[i] < goal)
                {
                    foreach (var x in 组合(arr, goal - arr[i], i + 1))
                        yield return new int[] { arr[i] }.Concat(x);
                }
            }
        }
    }
}
xuzuning 2018-04-28
  • 打赏
  • 举报
回复
用组合去实现是最直接的,但求组合的算法并不保证能按原始位置顺序排列(因为求组合的算法实现太多了),简单点的求组合算法还要求原始数据无重复项 https://ask.csdn.net/questions/687105 的算法是求组合算法的变形,但他利用了二进制数位,这就局限了待处理数据的规模 我的这个算法实际也是求组合算法的变形,利用栈消除递归 如在 default 分支中排除掉预期超限的数据,有可能提高效率,和减小栈的规模。 虽然最终无效组合都被删去了,但每次新增的待处理项的规模还是相当可观的
xuzuning 2018-04-28
  • 打赏
  • 举报
回复
        static void Main(string[] args)
{
int[] a = { 10, 8, 7, 7, 15, 13, 6, 6, 3, 3, 3, 4, 8, 9, 10, 13, 14 };
var sum = 50;

var res = new List<N>(); //结果缓冲区
for (var i = 0; i < a.Length; i++) res.Add(new N(i, a[i]));//初始化结果缓冲区
for (var i = 0; i < res.Count; i++)
{
var c = sum.CompareTo(res[i].v.Sum());
switch (c)
{
case 0: //达到目标
//res.Add(res[i]);
//tmp.RemoveAt(i--);
break;
case -1://大于目标就删去
res.RemoveAt(i--);
break;
default: //否则补充后续项
var k = i + 1;
for (var j = res[i].i+1; j < a.Length; j++)
{
var n = new N(j, res[i].v);
n.v.Add(a[j]);
//res.Add(n);//追加到尾部,不能保证顺序
res.Insert(k++, n);//插入到当前项后面
}
res.RemoveAt(i--);//删去当前项,因为不合要求
break;
}
}
Console.WriteLine("共找到 {0} 种组合", res.Count);
Console.WriteLine("前 20 种为:", res.Count);
foreach (var n in res.Take(20))
{
Console.WriteLine("{0} = {1}", n.v.Sum(), string.Join("+", n.v));
}
}
class N
{
public int i;
public List<int> v;
public N(int i, List<int> v)
{
this.i = i;
this.v = new List<int>(v);
}
public N(int i,int v)
{
this.i=i;
this.v = new List<int>(){v};
}
}
  • 打赏
  • 举报
回复
你自己修改一下需求描述:
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var list = new List<int> { 10, 8, 7, 7, 15, 13, 6, 6, 3, 3, 3, 4, 8, 9, 10, 13, 14 };
            var cnt = 0;
            var container=new List<IEnumerable<int>>();
            foreach (var r in 组合(list, 50).Take(20))
            {
                Console.Write("第{0}个组合:", ++cnt);
                foreach (var s in r)
                    Console.Write("{0} ", s);
                Console.WriteLine("  {0}次", r.Count());
            }
            Console.WriteLine("...................按任意键结束");
            Console.ReadKey();
        }

        static IEnumerable<IEnumerable<int>> 组合(List<int> arr, int goal)
        {
            for (var i = 0; i < arr.Count; ++i)
            {
                if (arr[i] == goal)
                    yield return new int[] { arr[i] };
                else if (arr[i] < goal)
                {
                    var arr1 = arr.ToList();
                    arr1.RemoveAt(i);
                    foreach (var x in 组合(arr1, goal - arr[i]))
                        yield return new int[] { arr[i] }.Concat(x);
                }
            }
        }
    }
}

110,567

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧