动态规划算法:

切割钢条问题:不同长度的钢条的价格是不同的,怎样切割获取的利润最大。

假设钢条的长度为n,怎样切割获取最大值

普通方法实现:

  private static int  UpDown(int  n, int[] price)
        {
            if(n==0)//回调函数的终止条件
            {
                return 0;
            }          
            int maxprice = 0;
            for (int i = 1; i <=n; i++)
            {
                int Value = price[i] + UpDown(n-i,price);//利用了分治算法,分开求不同段的钢条的最大值,price[i]是切割的固定的长度,Up()是利用回调函数获取这个长度的利润最大值
                if(maxprice<Value)
                {
                    maxprice = Value;
                }
            }
            return maxprice;
        }

动态算法实现钢条切割的最大利润

从顶到底实现:钢铁的切割

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Incise
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] price = new int[] { 0,1,5,8,9,10,17,17,20,24,30};
            int[] StartValue = new int[11];//因为我们要经常求某个长度的钢条的最大值,所以我们可以用数组存储我们已近算出来的某个长度的最大利润。
          //  int n = int.Parse(Console.ReadLine());
            int MaxPrice= UpDown(9 ,price,StartValue);
            Console.WriteLine(MaxPrice);
            Console.ReadKey();

        }
        /// <summary>
        /// 根据不同长度的钢条价格获取最好的切割方案
        /// </summary>
        /// <param name="n"></param>
        /// <param name="price"></param>
        /// <returns></returns>
        private static int  UpDown(int  n, int[] price,int[] StartValue)
        {
            if(n==0)//回调函数的终止条件
            {
                return 0;
            }   
            if(StartValue[n]!=0)//判断我们已经存储过这个值的最大利润时,可以直接使用最大利润
            {
                return StartValue[n];
            }       
            int maxprice = 0;
            for (int i = 1; i <=n; i++)
            {
                int Value = price[i] + UpDown(n-i,price,StartValue);//利用了分治算法,分开求不同段的钢条的最大值,price[i]是切割的固定的长度,Up()是利用回调函数获取这个长度的利润最大值
                if(maxprice<Value)
                {
                    maxprice = Value;
                }
            }
            StartValue[n] = maxprice;//算出n的最大利润后,我们把值存储在数组中,以后在使用这个长度时,可以直接使用
            return maxprice;
        }
    }
}

从底到顶的钢条切割:会优化这个算法

 private static int ButtonUp(int n,int[] price,int [] StartValue)
        {
            if(n==0)//结束回调函数的条件
            {
                return 0;
            }
            if(StartValue[n]!=0)//如果这个长度的钢条的最大利润已近计算出过,就直接把这个最大利润从数组中拿出来,直接使用
            {
                return StartValue[n];
            }
            int MaxValue = 0;
            for (int i = 1; i <=n; i++)//N是钢条的长度,对这个钢条分解求最大利润
            {
                int temp = 0;
                for (int j = 1; j <=i; j++)
                {
                    temp = price[j] + ButtonUp(i-j,price,StartValue);//从小到大的切割钢条,这样下一个钢条会直接使用上一个钢条的最大利润
                    if(temp>MaxValue)
                    {
                        MaxValue = temp;
                    }
                }
                StartValue[i] = MaxValue;
            }
            return StartValue[n];//StartValue数组中存储了,从0-n长度的钢条的最优解
        }

 动态规划解决背包问题

背包问题可以使用穷举法和动态规划算法

穷举法:计算出物品放入背包的各种可能,在判断每一种可能的重量是否超标,不超标的情况那个利润最大。核心思想是利用与运算得到每一种情况种的物品,用来计算利润

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MaxBack
{
    class Program
    {
        static void Main(string[] args)
        {          
            int Wht = 10;//背包的容量
            int[] price = new int[] {4,5,6 };//物品的价格
            int[] weight = new int[] { 3,4,5}; //物品的重量          
            Console.WriteLine(maxProfit(price, weight, Wht));//输出背包能放物品的最大利润
            Console.ReadKey();
        }
        /// <summary>
        /// 穷举法计算背包的最大利润
        /// </summary>
        /// <param name="price"></param>
        /// <param name="weight"></param>
        /// <param name="Wht"></param>
        /// <returns></returns>
        private static int maxProfit(int[] price, int[] weight, int Wht)
        {
            int MaxValue = 0;     //背包的最大利润    
            for (int i = 0; i < Math.Pow(2,weight.Length); i++)//背包放入物品的各种可能
            {         
                int temp = 0, temp1 = 0;
                for (int j = 0; j < weight.Length; j++)//用二进制的与运算计算出每一种可能的具体物品
                {                
                   if ((Convert.ToInt32(Math.Pow(2, j)) & i)== Convert.ToInt32(Math.Pow(2, j)))//与运算为1的值表示这个物品要放入背包中
                    {                    
                        temp += price[j];//计算每一种情况要放入背包物品的总价格
                        temp1 += weight[j];//计算每一种情况要放入背包物品的总重量
                        if(temp1>Wht)//总量超过背包物品的总重量时,终止放入,计算下一种情况
                        {
                            break;
                        }
                    }
                }
                if(temp1<=Wht)//判断放入背包的重量小于背包重量的各种情况的最大利润
                {
                    if(MaxValue<temp)
                    {
                        MaxValue = temp;
                    }
                }
            }
            return MaxValue;//返回这个最大利润
        }
    }
}

 

动态规划算法:每一次只判断一个物品是放入和不放入的利润谁大,利用嵌套调用。

 

使用动态规划算法,自上往下计算

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BacKQuestion
{
    class Program
    {
        /// <summary>
        /// 最大背包问题
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            int wht = 5;
            int[] Weight = new int[] { 0,3,4,5};
            int[] price = new int[] { 0,4,5,6};
            int value = MaxValue(wht, Weight, price, price.Length-1);
            Console.WriteLine(value);
            Console.ReadKey();
        }
        /// <summary>
        /// 使用动态规划算法,选则物品放入背包,以获取最大利润
        /// </summary>
        /// <param name="wht"></param>
        /// <param name="Weight"></param>
        /// <param name="price"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static int MaxValue(int wht,int[] Weight,int[] price,int index)
        {
            int Maxvalue1 = 0;
            int maxvalue2 = 0;
            if(index==0||wht==0)//当物品的个数为0时,或背包放不下时,结束放置物品
            {
                return 0;
            }
            if(wht<Weight[index])//第I个物体放入背包时超重,选择放入第I-1个物体
            {
                return MaxValue(wht, Weight, price, index - 1);//第i个物体放入时超重,选择放入第I-1个物体
            }
            else//第i个物体能放入背包中
            { 
                Maxvalue1 = MaxValue(wht-Weight[index],Weight,price,index-1)+price[index];//第I个物体放入背包,在判断第i-1个物体要不要放入背包
                maxvalue2 =MaxValue(wht, Weight, price, index-1);//第i个物体不放入背包,在判断第I-1个物体要不要放入背包
                return Maxvalue1 > maxvalue2 ? Maxvalue1 : maxvalue2;//获取这两种情况的最大值返回
            }                                  
        }
    }
}

背包问题:动态规划算法自上而下优化方法。用二维数组Array[weight,]记录每一种重量的最大利润,

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BacKQuestion
{
    class Program
    {
        /// <summary>
        /// 最大背包问题
        /// </summary>
        /// <param name="args"></param>
        public static int[,] array = new int[11, 4];//int[i,j]i表示背包容量,j表示存储的物品数量,用数组存储不同容量下背包的最大利润
        static void Main(string[] args)
        {
            int wht = 10;
            int[] Weight = new int[] { 0,3,4,5};
            int[] price = new int[] { 0,4,5,6};
            int value = MaxValue(wht, Weight, price, price.Length-1);
            Console.WriteLine(value);
            Console.ReadKey();
        }
        /// <summary>
        /// 使用动态规划算法,选则物品放入背包,以获取最大利润
        /// </summary>
        /// <param name="wht"></param>
        /// <param name="Weight"></param>
        /// <param name="price"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static int MaxValue(int wht,int[] Weight,int[] price,int index)
        {
            int Maxvalue1 = 0;
            int maxvalue2 = 0;
            if(index==0||wht==0)//当物品的个数为0时,或背包放不下时,结束放置物品
            {
                return 0;
            }
            if(array[wht,index]!=0)
            {
                return array[wht, index];
            }
            if(wht<Weight[index])//第I个物体放入背包时超重,选择放入第I-1个物体
            {
                array[wht,index-1]= MaxValue(wht, Weight, price, index - 1);//第i个物体放入时超重,选择放入第I-1个物体
                return array[wht,index-1];
            }
            else//第i个物体能放入背包中
            { 
                Maxvalue1 = MaxValue(wht-Weight[index],Weight,price,index-1)+price[index];//第I个物体放入背包,在判断第i-1个物体要不要放入背包
                maxvalue2 =MaxValue(wht, Weight, price, index-1);//第i个物体不放入背包,在判断第I-1个物体要不要放入背包
              
                if(Maxvalue1>maxvalue2)
                {
                    array[wht, index] = Maxvalue1;//记录当存储的空间为wht,放入物品与不放入物品时,把利润最大的值记录下来
                }
                else
                {
                    array[wht, index] = maxvalue2;
                }
            }
            return array[wht,index];                                
        }
    }
}

 

背包问题:使用动态算法自下而上记录每一种情况的最大利润

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ButtonToUp
{
    class Program
    {
        public static int[,] array = new int[13, 4];//int[i,j]i表示背包容量,j表示存储的物品数量,用数组存储不同容量下背包的最大利润
        static void Main(string[] args)
        {
            int wht = 12;
            int[] Weight = new int[] { 0, 3, 4, 5 };
            int[] price = new int[] { 0, 4, 5, 6 };
            int value = MaxValue(wht, Weight, price, price.Length - 1);
            Console.WriteLine(value);
            Console.ReadKey();
         
        }

        private static int MaxValue(int wht, int[] weight, int[] price, int v)
        {
            if(array[wht,v]!=0)//多次查找背包的最大利润时,如果这个值已近被记录下来,可以直接使用数组中存储的值
            {
                return array[wht, v];
            }
            for (int i = 1; i <=wht; i++)
            {
               
                for (int j = 1; j <=v; j++)
                {
                    if (array[i,j] != 0)//要查找的这个值虽然没存储在数组中,但他前面的可能性已近存储了,所以可以直接使用
                    {
                        return array[i,j];
                    }
                    if (i < weight[j])//如果这个物体的重量大于背包的重量,则这种情况不放入这个物体
                    {
                        array[i, j] = array[i, j - 1];
                    }
                    else//如果这个物体的重量小于背包的重量,物体可以放入也可以不放,判断那种情况的利润最大,把他记录下来
                    {
                        int Maxprice1 = price[j] + array[i-weight[j], j - 1];
                        int Maxprice2 = array[i, j - 1];
                        if (Maxprice1 > Maxprice2)
                        {
                            array[i, j] = Maxprice1;
                        }
                        else
                        {
                            array[i, j] = Maxprice2;
                        }
                    }
                }
            }
            return array[wht, v];//返回这个容量下的最大利润
        }
    }
}

 

posted on 2019-08-01 14:20  慕容锤  阅读(124)  评论(0编辑  收藏  举报