动态规划算法:
切割钢条问题:不同长度的钢条的价格是不同的,怎样切割获取的利润最大。
假设钢条的长度为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];//返回这个容量下的最大利润 } } }