分治法

分治算法
分治策略:对于一个规模为n的问题,若该问题比较容易解决(比如规模较小)则直接解决,否则将其分解为k个规模较小的子问题.这些子问题互相独立且与原问题形式相同,递归地解决这些子问题,然后将各子问题的解合并得到原问题解.这种算法设计策略叫做分治法.
分治法解决的问题:
(1),二分搜索
(2),最大整数乘法
(3),Strassen矩阵乘法
(4),棋盘覆盖
(5),合并排序
(6),快速排序
(7),线性时间选择排序
(8),最接近点对问题
(9),循环赛日程表
(10),汉诺塔

例:
最大子数组问题
天数: 1 2 3 4 5 6
价格: 12 15 15 16 13 15
变化: 3 0 1 -3 2

3 0 1 -3 2
low mid high

共3种情况:
1,最大子数组开始下标,结束下标都在[low,mid]范围内
2,最大子数组开始下标,结束下标都在[mid,high]范围内
3,最大数组开始下标在mid前,结束下标在mid+1后.

相对3种情况:
相对于上面1 2两种情况采用递归方法。
    分治法在每一层递归上都有三个步骤:
    分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
    解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;
    合并:将各个子问题的解合并为原问题的解。
第3种就直接for查找在mid前的开始下标和mid+1后的结束下标,然后把两个计算和相加就好了。
代码块:
//最大子数组问题
    class Program
    {
        //暴力求解
        void Violence()
        {
            int[] priceArray = { 12, 15, 15, 16, 13, 15 };
            int[] priceFluctuationArray = new int[priceArray.Length - 1];//价格波动的数组
            for (int i = 1; i < priceArray.Length; i++)
            {
                priceFluctuationArray[i - 1] = priceArray[i] - priceArray[i - 1];
            }
            int total = priceFluctuationArray[0];//默认第一个数元素是最大数组
            int startIndex = 0;
            int endIndex = 0;
            for (int i = 0; i < priceFluctuationArray.Length; i++)
            {
                //取得以i为子数组起点的所有子数组
                for (int j = i; j < priceFluctuationArray.Length; j++)
                {
                    //由i,j就确定了一个子数组
                    int totalTemp = 0;
                    //临时最大子数组的和
                    for (int index = 0; index < j+1; index++)
                    {
                        totalTemp += priceFluctuationArray[index];
                    }
                    if (totalTemp>total)
                    {
                        total = totalTemp;
                        startIndex = i;
                        endIndex = j;
                    }
                }
            }
            Console.WriteLine("---暴力法:");
            Console.WriteLine("买入日期:" + (++startIndex));
            Console.WriteLine("卖出日期:" + (endIndex+2));
            Console.WriteLine("总盈利:" + total);
        }

        //存放左右边界值以及sum值的结构体
        /*特别注意结构体的使用!!!!!!!!!!!*/
        struct SubArray 
        {
           public  int startIndex;//左部边界下标
            public  int endIndex;//右部边界下标
            public  int total;//左右边界之间的数组元素和
        }

        //分治法
        void DivideAndConquer()
        {
            int[] priceArray = { 12, 15, 15,16, 13,15};
            int[] pf = new int[priceArray.Length - 1];//价格波动的数组
            for (int i = 1; i < priceArray.Length; i++)
            {
                pf[i - 1] = priceArray[i] - priceArray[i - 1];
            }
            SubArray subArray = GetMaxSubArray(0, pf.Length - 1, pf);
            Console.WriteLine();
            Console.WriteLine("---分治法:");
            Console.WriteLine("买入日期:"+(subArray.startIndex+1));
            Console.WriteLine("卖出日期:"+(subArray.endIndex+2));
            Console.WriteLine("总盈利:"+subArray.total);
        }

        //这个方法是用来取得array这个数组从low到high之间的最大子数组
        SubArray GetMaxSubArray(int low,int high,int[] array)
        {
            if (low==high)
            {
                SubArray subarray;
                subarray.startIndex = low;
                subarray.endIndex = high;
                subarray.total = array[low];
                return subarray;
            }

            int mid = (low + high) / 2;//低区间 [low,mid] 高区间 [mid-1,high]

            SubArray subArray1 = GetMaxSubArray(low, mid, array);

            SubArray subArray2 = GetMaxSubArray(mid + 1, high, array);

            //从[low,mid]找到最大子数组[i,mid]
            int total1 = array[mid];
            int startIndex = mid;
            int totalTemp = 0;
            for (int i = mid; i >= low; i--)
            {
                totalTemp += array[i];
                if (totalTemp > total1)
                {
                    total1 = totalTemp;
                    startIndex = i;
                }
            }
            //从[mid+1,high]找到最大子数组[mid+1,j]
            int total2 = array[mid + 1];
            int endIndex = mid + 1;
            totalTemp = 0;
            for (int j = mid+1; j <= high; j++)
            {
                totalTemp += array[j];
                if (totalTemp>total2)
                {
                    total2 = totalTemp;
                    endIndex = j;
                }
            }

            SubArray subArray3;
            subArray3.startIndex = startIndex;
            subArray3.endIndex = endIndex;
            subArray3.total = total1 + total2;
            if (subArray1.total >= subArray2.total && subArray1.total >= subArray3.total)
            {
                return subArray1;
            }
            else if (subArray2.total >= subArray1.total && subArray2.total >= subArray3.total)
            {
                return subArray2;
            }
            else
            {
                return subArray3;
            }
        }
        static void Main(string[] args)
        {
            Program a =new Program();
            a.Violence();
            a.DivideAndConquer();
            Console.ReadLine();
        }
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值