码迷,mamicode.com
首页 > 其他好文 > 详细

背包问题解决实际问题的应用-船只运送货物

时间:2020-07-04 19:13:14      阅读:73      评论:0      收藏:0      [点我收藏+]

标签:一个   alt   穷举   tostring   add   大于   reac   ring   lis   

  现在有个问题:已知N个箱子以及每个箱子重量,船只最大承载量是W,如何在T次运送之内运完箱子(不考虑空间因素,只要重量没超过都能放得下)

   思路:要保证在T次之内送完箱子,换句话说就要要每次运送的货物的总重量达到或者最接近船只最大承载量(当然前提要保证最大承载量W大于(箱子总重量/T次)

  方法1:穷举所有可能性数组,然后计算其中数组最大值,就能算出这次最优解,但是缺点非常的明细当有2位数箱子时可能性数组会占用大量内存基本上内存会溢出,所以这方法就不考虑了

  方法2:贪婪算法,但是贪婪算法是以特定情况下解出最优解,无法算出全部情况的最优解所以也不考虑

  方法3:0-1背包问题,其核心想法就是采用动态递推的方式算出当前最优解,是一种组合优化的NP完全问题

  • 0-1背包问题

  我们先介绍一下如何用背包问题解决的具体思路:

  首相我们第一个F(i,W)为前i个箱子中挑选不超过W重量的箱子,使得此次挑选的总重量最大 ,最大值记做M(i,W),要考虑第i次的最优解就是考虑i-1的基础上是否继续搬运第i个箱子

  1. 选第i个箱子,问题就变成F(i-1,W-wi)

  2. 不选,问题就变成F(i-1,w)

   最优解就是在比较 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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!