zoukankan      html  css  js  c++  java
  • 分治算法-最大子数组问题

    1.蛮力法求解

    总体思路:

      蛮力法是最简单的实现方法,只要列出数组所有可能的组合,然后找出其中和最大的组合即可;

      蛮力法分三层循环实现:

        1)第一层循环用于固定子数组的起始位置;

        2)第二层循环用于确定子数组的结束位置;

        3)第三层循环用于子数组和的计算,从子数组的头开始遍历到其尾,累加起来就是该子数组的和。

    实现:

       /// <summary>
            /// 暴力求解
            /// </summary>
            /// <param name="priceArray"></param>
            /// <param name="priceFlutuationsArray"></param>
            public static void Violentsolution(int[] priceArray,int[] priceFlutuationsArray)
            {
                int total = priceFlutuationsArray[0];//默认数组得第一个元素 是最大子数组
                int StartIndex = 0;
                int EndIndex = 0;
    
                for (int i = 0; i < priceFlutuationsArray.Length; i++)
                {
                    //取得以i为子数组起点得 所有子数组
                    for (int j = i; j < priceFlutuationsArray.Length; j++)
                    {
                        //由i j就确定了一个子数组
                        int totalTemp = 0;//临时最大子数组得和
                        for (int k = i; k < j + 1; k++)
                        {
                            totalTemp += priceFlutuationsArray[k];
                        }
                        if (totalTemp > total)
                        {
                            total = totalTemp;
                            StartIndex = i;
                            EndIndex = j;
                        }
                    }
                }
                Console.WriteLine("start:" + StartIndex);
                Console.WriteLine("End:" + EndIndex);
                Console.WriteLine("购买日期是第" + StartIndex + "天 出售日期是第" + (EndIndex + 1) + "");
                Console.WriteLine("total:" + total);
            
              }

    2.分治法求解

    总体思路:

      分治法的精髓:
        1)分--将问题分解为规模更小的子问题;
        2)治--将这些规模更小的子问题逐个击破;
        3)合--将已解决的子问题合并,最终得出“母”问题的解;
      所以原数组的最大子数组求法:
        1)分--将原数组拆分成两部分,每个部分再拆分成新的两部分......直到数组被分得只剩下一个元素;
        2)治--每个小型的数组找最大子数组,只有一个元素的数组,解就是该元素;
        3)合--将两个小型数组合并为一个数组,其中解有三种可能:
        • 左边的返回值大,
        • 右边的返回值大,
        • 中间存在一个更大的子数组和;
         返回值应选最大的;

    实现:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 最大子数组问题
    {
        class Program
        {
            //最大子数组的结构体
            struct SubArray
            {
                public int startIndex;
                public int endIndex;
                public int total;
            }
            static void Main(string[] args)
            {
                int[] priceArray = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 };
                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(subArray.startIndex);
                Console.WriteLine(subArray.endIndex);
                Console.WriteLine("我们在第" + subArray.startIndex + "天买入, 在第" + (subArray.endIndex + 1) + "天卖出");
                Console.ReadKey();
            }
    
            /// <summary>
            /// 这个方法用来取得array这个数组从low到high得最大子数组
            /// </summary>
            /// <param name="low"></param>
            /// <param name="high"></param>
            /// <param name="array"></param>
             static 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);
    
                SubArray subArray3 = GetMaxSub(low, mid, high, array);
    
                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 SubArray GetMaxSub(int low,int mid,int high,int[] 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;
                return subArray3;
            }
        }
    }
  • 相关阅读:
    CF703D Mishka and Interesting sum
    CF697D Puzzles
    SCOI2017酱油记
    [BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏
    BZOJ4311:向量
    BZOJ4520: [Cqoi2016]K远点对
    BZOJ4555: [Tjoi2016&Heoi2016]求和
    [Codechef November Challenge 2012] Arithmetic Progressions
    agc040
    补题
  • 原文地址:https://www.cnblogs.com/rongweijun/p/8177354.html
Copyright © 2011-2022 走看看