zoukankan      html  css  js  c++  java
  • 动态规划法-01背包问题

    一 几个概念:

    最优化问题:有n个输入,它的解由这n个输入的一个子集组成,这个子集必须满足某些事先给定的条件,这些条件称为约束条件,满足约束条件的解称为问题的可行解。满足约束条件的可行解可能不止一个,为了衡量这些可行解的优劣,事先给出一定的标准,这些标准通常以函数的形式给出,这些标准函数称为目标函数,使目标函数取得极值的可行解成为最优解,这类问题称为最优化问题。


    二 最优性原理:

    对于一个具有n个输入的最优化问题,其求解的过程往往能够划分为若干个阶段,每个阶段的决策仅依赖前一阶段的状态,由决策所採取的动作使状态发生转移,成为下一个阶段的根据。从而,一个决策序列在不断变化的状态中产生。这个决策序列产生的过程称为多阶段决策过程。

    在每个阶段的决策中有一个赖以决策的策略或目标,这样的策略或目标是由问题的性质和特点所确定,通常以函数的形式表示并具有递推关系,称为动态规划函数。

    多阶段决策过程满足最优性原理:不管决策过程的初始状态和初始决策是什么,其余决策必须相对于初始决策所产生的当前状态,构成一个最优决策序列。

    假设一个问题满足最优性原理通常称此问题具有最优子结构性质

    三 特征

    我们知道动态规划是求解全局最优解的有效方法,一般来说能用动态规划算法求解的问题具有下面两个显著特称:

    • 具有最优子结构性质,也就是说能够递归的定义最优解。

    • 可以分解为相互重叠的若干自问题。

    • 最优解中也包括其子问题的最优解。


    四 设计方案

    动态规划法设计方案

    • 分段:将原问题分解为若干个相互重叠的子问题;

    • 分析:分析问题是否满足最优子结构性质,找出动态规划函数递推式;

    • 求解:利用递推式自底向上计算,实现动态规划过程。


    五 01背包问题

    0/1背包问题中,物品i或者被放入背包,或者不被放入背包,设Xi表示物品i装入背包的情况,则当Xi=0时,表示物品i没有被装入背包,Xi=1时,表示物品i被装入背包。依据问题的要求,有例如以下约束条件和目标函数:

    图 1 约束条件


    图2 目标函数

    01背包的状态转换方程f[i,j]= Max{ f[i-1,j-Wi]+Pi( j >= Wi ),  f[i-1,j] }

    f[i,j]表示在前i件物品中选择若干件放在承重为j的背包中,能够取得的最大价值。

    Pi表示第i件物品的价值。

    决策:为了背包中物品总价值最大化,第i件物品应该放入背包中吗?

    六 动态规划法解决方式

    有编号分别为a,b,c,d,e的五件物品,它们的重量各自是2,2,6,5,4,它们的价值各自是6,3,5,4,6,如今给你个承重为10的背包,怎样让背包里装入的物品具有最大的价值总和

    name

    weight

    value

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    a

    2

    6

    0

    6

    6

    9

    9

    12

    12

    15

    15

    15

    b

    2

    3

    0

    3

    3

    6

    6

    9

    9

    9

    10

    11

    c

    6

    5

    0

    0

    0

    6

    6

    6

    6

    6

    10

    11

    d

    5

    4

    0

    0

    0

    6

    6

    6

    6

    6

    10

    10

    e

    4

    6

    0

    0

    0

    6

    6

    6

    6

    6

    6

    6

    10/1背包问题动态规划法

    1採用自底向上自左向右的方式生成的。

    e1表示在背包容量为1的情况下只放入物品e的价值,因容量1<4因此价值为0;依此类推当背包容量为4时,单元格e4的价值为6。容量继续上涨也只能放置e,因此价值持续为6

    d行可參照递推式f[i,j]= Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }例如以下描写叙述

    1. i<=5时,d行表格价值与e行同样;

    2. i>=6时,比方第6行,选取Max{f[1,1]+4,f[1,6]}Max{e1+4, e6}=Max{4, 6} = 6;依此类推d9=Max{f[1,4]+4,f[1,59}=10;

    依次类推可计算c/b/a的值,然后依据最大价值返算最优路径。


    d1表示背包容量为1的情况下放置物品de后的价值,因e的重量为4>1,且d的重量为5>1因此价值为0。直至第5(不包含d5)d行表格的内容与e行同样,



    七 程序实现C#

    代码段1 測试函数

    class MainClass
    	{
    		public static void Main (string[] args)
    		{
                Obj[] objs = new Obj[4];
                objs[0] = new Obj() { Weight = 7, Price = 42 };
                objs[1] = new Obj() { Weight = 3, Price = 12 };
                objs[2] = new Obj() { Weight = 4, Price = 40 };
                objs[3] = new Obj() { Weight = 5, Price = 25 };
    
    
                			Console.WriteLine ("Dynamicprogramming Model:");            
    			dynamicprogramming d = new dynamicprogramming (objs, 10);
    			int price = d.Execute ();
    			d.Printing (price);
                //Console.Read();
    		}
    	}

    代码段2 实现函数


    public class dynamicprogramming
    	{
    		/// <summary>
    		/// 存储动态规划的递推数据
    		/// m_V[i][j]表示前i个物品放入容量为j的背包获得的最大价值
    		/// 当中第0行作为初始化,表示不放入物品时的价值;
    		/// 第0列作为初始化,表示容量为0时能放入物品的价值;
    		/// </summary>
    		private int[,] m_V;
    		/// <summary>
    		/// 物品数量
    		/// </summary>
    		private int m_n;
    		/// <summary>
    		/// 背包容量
    		/// </summary>
    		private int m_w;
    
    		public Obj[] objs {
    			get;
    			set;
    		}
    		public dynamicprogramming (Obj[] objs, int w)
    		{
    			if (objs == null) {
    				return;
    			}
    
    			m_n = objs.Length;
    			this.objs = objs;
    			m_w = w;
    			m_V = new int[m_n + 1, m_w + 1];
    
    			for (int i = 0; i < m_w+1; i++) {
    				m_V [0, i] = 0;
    			}
    			for (int i = 0; i < m_n+1; i++) {
    				m_V [i, 0] = 0;
    			}
    		}
    
    		public int Execute()
    		{
    			for (int r = 1; r <= m_n; r++) {
    				for (int w = 1; w <= m_w; w++) {
    					if (w < objs[r - 1].Weight) {
    						m_V[r, w] = m_V[r - 1, w];
    					} else {
    						int tmp = m_V [r - 1, w - objs [r - 1].Weight] + objs [r - 1].Price;
    						m_V [r, w] = m_V [r - 1, w] > tmp ? m_V [r - 1, w] : tmp;
    					}
    				}
    			}
    
    			//求装入背包的物品
    			int weight = m_w;
    			for (int i = m_n; i > 0; i--) {
    				if (m_V[i, weight] > m_V[i - 1, weight]) {
    					objs [i - 1].Selected = true;
    
    					weight -= objs [i - 1].Weight;
    				}
    			}
    
    			return m_V[m_n, m_w];
    		}
    
    		public void Printing(int price)
    		{
    			Console.Write("<");
    			for (int i = 0; i < objs.Length; i++)
    			{
    				Console.Write(objs[i].Selected ? "1 " : "0 ");
    
    			}
    			Console.WriteLine(">, price: " + price );
    		}
    	}

    输出结果:

    注:上述程序使用FreeBSD下Mono开发。


  • 相关阅读:
    Pthread使用总结
    OpenCV同态滤波
    重复文件重新创建
    Consider using the `--user` option or check the permissions.
    错误:pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.
    python tkinter模版
    tkinter页面卡死
    视频下载
    tkinter学习系列(三)之Label控件
    Entry小部件:
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/3867254.html
Copyright © 2011-2022 走看看