标签:一个 alt 穷举 tostring add 大于 reac ring lis
现在有个问题:已知N个箱子以及每个箱子重量,船只最大承载量是W,如何在T次运送之内运完箱子(不考虑空间因素,只要重量没超过都能放得下)
思路:要保证在T次之内送完箱子,换句话说就要要每次运送的货物的总重量达到或者最接近船只最大承载量(当然前提要保证最大承载量W大于(箱子总重量/T次))
方法1:穷举所有可能性数组,然后计算其中数组最大值,就能算出这次最优解,但是缺点非常的明细当有2位数箱子时可能性数组会占用大量内存基本上内存会溢出,所以这方法就不考虑了
方法2:贪婪算法,但是贪婪算法是以特定情况下解出最优解,无法算出全部情况的最优解所以也不考虑
方法3:0-1背包问题,其核心想法就是采用动态递推的方式算出当前最优解,是一种组合优化的NP完全问题
我们先介绍一下如何用背包问题解决的具体思路:
首相我们第一个F(i,W)为前i个箱子中挑选不超过W重量的箱子,使得此次挑选的总重量最大 ,最大值记做M(i,W),要考虑第i次的最优解就是考虑i-1的基础上是否继续搬运第i个箱子
最优解就是在比较 F(i-1,W-wi),F(i-1,w)中的最大值
1 //寻找一次性搬运不超过maxWeight重量的最优解 2 static String[] getMax(int[] w, int maxWeight) 3 { 4 //初始化最优解数组 5 int[,] p = new int[w.Length + 1, maxWeight + 1]; 6 //初始化 要搬运箱子重量 7 String[,] strIndex = new String[w.Length + 1, maxWeight + 1]; 8 for (int i = 0; i < p.GetLength(0); i++) 9 { 10 for (int j = 0; j < p.GetLength(1); j++) 11 { 12 if (i == 0 || j == 0) 13 { 14 p[i, j] = 0; 15 strIndex[i, j] = ""; 16 } 17 else 18 { 19 //第i件箱子的在重量小于等于j时能够放入船内 20 if ((j - w[i - 1]) >= 0) 21 { 22 //总重量是否小于上次总重量 23 p[i, j] = p[i - 1, j - w[i - 1]] + w[i - 1] > p[i - 1, j] ? p[i - 1, j - w[i - 1]] + w[i - 1] : p[i - 1, j]; 24 strIndex[i, j] = p[i - 1, j - w[i - 1]] + w[i - 1] > p[i - 1, j] ? strIndex[i - 1, j - w[i - 1]] + " " + w[i - 1].ToString() : strIndex[i - 1, j]; 25 } 26 else//第i件箱子在重量大于j时不能放入船内.总重量就为i-1重量 27 { 28 p[i, j] = p[i - 1, j]; 29 strIndex[i, j] = strIndex[i - 1, j]; 30 } 31 } 32 } 33 } 34 string[] arrW = strIndex[w.Length, maxWeight].Trim().Split(‘ ‘); 35 return arrW; 36 }
其中strIndex 为了记录最优解的箱子重量,p记录最优解的总重量
1 static void Main(string[] args) 2 { 3 while (true) 4 { 5 Console.WriteLine("输入船只最大载重量"); 6 string strMax = Console.ReadLine(); 7 int maxBox = 0; 8 if (!int.TryParse(strMax, out maxBox)) 9 { 10 Console.WriteLine("请正常输入数字"); 11 return; 12 } 13 Console.WriteLine("输入船只要运送的次数"); 14 string strTimes = Console.ReadLine(); 15 int times = 0; 16 if (!int.TryParse(strTimes, out times)) 17 { 18 Console.WriteLine("请正常输入数字"); 19 return; 20 } 21 Console.WriteLine("输入各箱子重量,空格分开,回车键结束"); 22 string weights = Console.ReadLine(); 23 string[] arrWeight = weights.Split(‘ ‘); 24 List<int> listWeight = new List<int>(); 25 int countWeight = 0; 26 foreach (string weight in arrWeight) 27 { 28 int temp = 0; 29 if (!int.TryParse(weight, out temp)) 30 { 31 Console.WriteLine("请正常输入数字"); 32 return; 33 } 34 if (temp > maxBox) 35 { 36 Console.WriteLine("都比船要大了,不送"); 37 return; 38 } 39 countWeight += temp; 40 listWeight.Add(temp); 41 } 42 float aver = countWeight / listWeight.Count; 43 if (maxBox < aver) 44 { 45 Console.WriteLine("这趟没发送了,每趟都要比船重"); 46 return; 47 } 48 List<List<int>> listResult = new List<List<int>>(); 49 //寻找最优解 50 while (listWeight.Count > 0) 51 { 52 string[] arrW = getMax(listWeight.ToArray(), maxBox); 53 List<int> listW = new List<int>(); 54 foreach (string w in arrW) 55 { 56 int temp = Convert.ToInt32(w); 57 listW.Add(temp); 58 listWeight.Remove(temp); 59 } 60 listResult.Add(listW); 61 } 62 63 for (int i = 0; i < listResult.Count; i++) 64 { 65 Console.Write("第{0}躺运送:", i + 1); 66 for (int j = 0; j < listResult[i].Count; j++) 67 { 68 Console.Write("{0} ", listResult[i][j]); 69 } 70 Console.WriteLine(""); 71 } 72 if (listResult.Count > times) 73 { 74 Console.WriteLine("无法在{0}躺之内运送成功,重新输入", times); 75 return; 76 } 77 78 Console.WriteLine("再来测试一下你吧!"); 79 } 80 }
最重要在while代码块:寻找i趟最优解之后,移除对应箱子重新寻找i+1趟的最优解
运行结果
代码下载地址:提取码pt12
算法参考地址:https://zhuanlan.zhihu.com/p/30959069
标签:一个 alt 穷举 tostring add 大于 reac ring lis
原文地址:https://www.cnblogs.com/chenpdev/p/13235579.html