和差值最小子数组划分

有一个数列,要采取怎样的划分方法把它分成2个数列,使得2个数列的各自之和的差最小。

比如一个数列(5,8,13,27,14),通过分成(5,13,14)和(8,27),这样2个数列各自的和再作差就等于35-32=3,这样差值最小。

暂时有两种想法可以做,现在只给出第一种的代码(C#)

1.      动态规划

(1)就是根据输入数组的长度(N),把这个问题看成一个N歩动态规划的问题。

(2)对于动态规划,需要有状态变量记录当前的状态(这里有当前歩i,前面的选择情况,当前的差值);

(3)对于每一步的选择有两种,比如第i歩时,选择将第i个数放入数组1或者数组2。

最后的实现就是递归状态变量得到。

2.      枚举所有可能的差值

(1)      对于有限的数组,算出所有数分成两组可能的绝对值是可能的。

(2)      通过递归的形式,将长度大于2的数组,划分为两个较小的数组,然后分别计算它们可能得到的差值。然后再定义,两个子数组差值合并的计算方法和数组长度为2时的计算方法即可。

(3)      对于两个子数组差值合并的计算,把差值按照一定顺序排列,建立每个差值和整个数组分组的对应关系,所以不用记录每个差值对应的分组。

最后的实现就是递归数组得到。

        struct choiceSet
        {
            public int choice;
            public int value;
            public int position;
        }
        public static int minVal = 0, choiceFinal = 0;
        static void Main(string[] args)
        {
            List<int> originalList = new List<int>();
            string input = Console.ReadLine();
            char splitcomma = ',';
            string[] temp = input.Split(splitcomma);
            foreach (string s in temp)
            {
                originalList.Add(getNum(s));
                minVal += Convert.ToInt32(getNum(s));
            }
            choiceSet cs0;
            cs0.choice = 1;
            cs0.value = 0;
            cs0.position = 0;
            stepOne(originalList, cs0);
            writeResult(originalList, choiceFinal);
            Console.ReadKey();
        }

        static void writeResult(List<int> li, int choice)
        {
            Console.WriteLine("[Value,Group]");
            for (int i = 0; i < li.Count; i++)
            {
                Console.WriteLine("[{0},{1}]", li[li.Count-1-i], choice % 2 + 1);
            choice=(choice-choice%2)/2;
            }
            Console.WriteLine("The difference is {0}.",minVal);
        }

        static void stepOne(List<int> li, choiceSet cs)
        {
            if (cs.position == 0)
            {
                choiceSet cs1;
                cs1.choice = cs.choice * 2 + 0;
                cs1.value = cs.value + li[cs.position];
                cs1.position = cs.position + 1;
                stepOne(li, cs1);
            }
            else if (cs.position < li.Count - 1)
            {
                choiceSet cs1, cs2;
                cs1.choice = cs.choice * 2 + 0;
                cs1.value = cs.value + li[cs.position];
                cs1.position = cs.position + 1;
                cs2.choice = cs.choice * 2 + 1;
                cs2.value = cs.value - li[cs.position];
                cs2.position = cs.position + 1;
                stepOne(li, cs1);
                stepOne(li, cs2);
            }
            else
            {
                if (Math.Abs(cs.value + li[cs.position]) <= Math.Abs(cs.value + li[cs.position]))
                {
                    int fValue = cs.value + li[cs.position];
                    if (Math.Abs(fValue) < Math.Abs(minVal))
                    {
                        minVal = fValue;
                        choiceFinal = cs.choice * 2 + 0;
                    }



                }
                else
                {
                    int fValue = cs.value - li[cs.position];
                    if (Math.Abs(fValue) < Math.Abs(minVal))
                    {
                        minVal = fValue;
                        choiceFinal = cs.choice * 2 + 1;
                    }
                
                }
            }
        }

        static int getNum(string s)
        {
            char[] temp = s.ToCharArray();
            int sign = 1;
            int sum = 0;
            foreach (char c in temp)
            {
                if (c == '-')
                    sign = -1;
                else
                    sum = sum * 10 + ((int)c - 48);
            }
            return sum * sign;
        }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值