日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从背包问题优化详解动态规划思想

發布時間:2025/3/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从背包问题优化详解动态规划思想 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

動態規劃:

所有的數據結構與算法的理解必須建立在題目的練習上,否則看多少理論都沒有實際用處!!!

所以下面這些理論文字看不懂通通沒關系,跟隨下面的背包問題還會跟深入的理解。

一、基本概念:任何數學遞推公式都可以直接轉換成遞歸算法,但是基本現實是編譯器常常不能正確對待遞歸算法,結果導致低效的程序。當懷疑很可能是這種情況是,我們必須給編譯器提供一些幫助,將遞歸算法重新寫成非遞歸算法讓后者把這些子問題的答案系統地記錄在一個表內。利用這種方法的一種技巧叫做動態規劃。根據《數據結構與算法分析--Java語言描述》原書第三版?中給動態規劃(DP)的定義(出自《數據結構與算法分析--Java語言描述》原書第三版?


二、主要分類:動態規劃一般可分為線性動規,區域動規,樹形動規,背包動規四類。
舉例:
線性動規:攔截導彈,合唱隊形,挖地雷,建學校,劍客決斗等;
區域動規:石子合并, 加分二叉樹,統計單詞個數,炮兵布陣等;
樹形動規:貪吃的九頭龍,二分查找樹,聚會的歡樂,數字三角形等;
背包動規:01背包問題,完全背包問題,分組背包問題,二維背包,裝箱問題,擠牛奶等;
除此之外還有許多變形的動態規劃問題,再次不一一列舉。


三、動態規劃問題中的術語(這一部分看不懂沒關系,用處不大)

階段:把所給求解問題的過程恰當地分成若干個相互聯系的階段,以便于求解,過程不同,階段數就可能不同。描述階段的變量稱為階段變量。
狀態:狀態表示每個階段開始面臨的自然狀況或客觀條件,它不以人們的主觀意志為轉移,也稱為不可控因素。在具體題目中,狀態就是某階段的出發位置,它既是該階段某路的起點,同時又是前一階段某支路的終點。
無后效性:我們要求狀態具有下面的性質:如果給定某一階段的狀態,則在這一階段以后過程的發展不受這階段以前各段狀態的影響,所有各階段都確定時,整個過程也就確定了。狀態的這個性質意味著過程的歷史只能通過當前的狀態去影響它的未來的發展。
決策:一個階段的狀態給定以后,從該狀態演變到下一階段某個狀態的一種選擇(行動)稱為決策。在最優控制中,也稱為控制。因狀態滿足無后效性,故在每個階段選擇決策時只需考慮當前的狀態而無須考慮過程的歷史。
策略:由每個階段的決策組成的序列稱為策略。集合中達到最優效果的策略稱為最優策略。

最優化原理:作為整個過程的最優策略,它滿足:相對前面決策所形成的狀態而言,余下的子策略必然構成“最優子策略”。一個問題滿足最優化原理也稱其擁有最優子結構性質。最優性原理實際上是要求問題的最優策略的子策略也是最優


四、基本思想:動態規劃思想通常用于求解具有某種最優性質的問題。在這類問題中,可能會有許多可行解。其基本思想也是將待求解問題分解成若干個子問題,先求解子問題,然后從這些子問題的解得到原問題的解。但是適合于用動態規劃求解的問題,經分解得到子問題往往不是互相獨立的。如果我們能夠保存已解決的子問題的答案,而在需要時再找出已求得的答案,這樣就可以避免大量的重復計算。我們可以用一個表來記錄所有已解的子問題的答案。不管該子問題以后是否被用到,只要它被計算過,就將其結果填入表中。


五、解題思路:

1.找出最優解的性質,刻畫其結構特征和最優子結構特征;
2.遞歸地定義最優值,刻畫原問題解與子問題解間的關系,找到狀態方程
3.以自底向上的方式計算出各個子問題最優解,并避免子問題的重復計算
4.根據計算最優值時得到的信息,構造最優解。




01背包

問題描述:

有N件物品和一個容量為C的背包。第i件物品的體積是v[i],價值是w[i]。求解將哪些物品裝入背包可使價值總和最大。

?從這個題目中可以看出,01背包的特點就是:每種物品僅有一件,可以選擇放或不放

輸入:第一行兩個數據,物品件數N,背包容量C

接下來N行,每行對應第i件物品的體積v[i]和價值w[i]

Input:

3 9

1 2

2 3

3 1

Output:

6



思路一:逆向規劃

我們假定當前階段的狀態d(i, j)表示當前第i層,將從第i個到第n個物品裝入容量為j的背包所能達到的最大重量

由此,規劃的終點就是d(1, c)[即代表將第1,2,3,...,n個物品裝入容量為G的背包中所能達到的最大重量]

規劃的起點就是d(n, 0) 或 d(n, c)

如果我們不放物品i,狀態轉移為d(i+1, j),即將物品i+1放入剩余容量仍為j的背包中的價值

如果我們放入物品i,狀態轉移為d(i+1, j-v[i])+w[i], 即將物品i+1放入剩余容量為j-v[i]的背包中的價值

狀態轉移方程:d(i, j) = max{d(i+1, j), d(i+1, j-v[i]) + w[i]}

import java.util.Scanner;public class Main {static Scanner in = new Scanner(System.in);static int[] v,w;static int[][] d;static int n, c;public static void main(String[] args) {n = in.nextInt();c = in.nextInt();v = new int[n+1];w = new int[n+1];d = new int[n+2][c+1];for (int i = 1; i <= n; i++) {v[i] = in.nextInt();w[i] = in.nextInt();}for(int i = n; i >= 1; i--) {for(int j = 0; j <= c; j++) {d[i][j] = (i==n ? 0 : d[i+1][j]);if(j >= v[i]) {d[i][j] = Math.max(d[i][j],d[i+1][j-v[i]]+w[i]);}}}System.out.println(d[1][c]);} }

思路二:正向規劃

我們假定當前階段的狀態d(i, j)表示當前第i層,將前i個物品裝入容量為j的背包所能達到的最大重量

規劃的起點d(1, 0) 或 d(1, c)

規劃的終點d(n ,c)

狀態轉移方程:d(i, j) = max{d(i-1, j), d(i-1, j-v[i]) + w[i]}


import java.util.Scanner;public class Main {static Scanner in = new Scanner(System.in);static int[] v,w;static int[][] d;static int n, c;public static void main(String[] args) {n = in.nextInt();c = in.nextInt();v = new int[n+1];w = new int[n+1];d = new int[n+1][c+1];for(int i = 1; i <= n; i++) {int v = in.nextInt();int w = in.nextInt();for(int j = 0; j <= c; j++) {d[i][j] = (i==1 ? 0 : d[i-1][j]);if(j >= v) {d[i][j] = Math.max(d[i][j],d[i-1][j-v]+w);}}}System.out.println(d[n][c]);} } 思路一與思路二區別: 1. 正向規劃可以在輸入v, w的過程中處理數據,節省空間;在打印結果的時候不方便 2. 逆向規劃可以保證打印結果時最小字典序;需要存儲v, w



下面引入一個概念 滾動數組:形態上是一個一維數組,其作用在于可以優化空間,主要應用在遞推或動態規劃中(尤其是在背包問題中)。 由于DP題目是一個自底向上的擴展過程,我們常常需要用到的是連續的解,當一個狀態轉移到另一個狀態時,大多數情況下,之前存儲的狀態信息已經無用了,往往可以舍去。所以用滾動數組優化是很有效的。 好處:利用滾動數組可以在N很大的情況下達到壓縮存儲的作用。滾動數組在時間上并沒有什么改善,但是能節省很大的空間。 不足:由于沒有存儲之前的數據,所以在實現打印方面十分困難

思路三:用滾動數組實現

我們假定當前階段的狀態d(j)表示將當前物品裝入容量為 j 的背包所能達到的最大重量

規劃的起點d( 0 )

規劃的終點d( c )

狀態轉移方程:d( j ) = max{d( j ), d( j - v) + w}

import java.util.Scanner;public class Main {static Scanner in = new Scanner(System.in);static int[] v, w, d;static int n, c;public static void main(String[] args) {n = in.nextInt();c = in.nextInt();v = new int[n+1];w = new int[n+1];d = new int[c+1];for (int i = 1; i <= n; i++) {int v = in.nextInt();int w = in.nextInt();for (int j = c; j >= 0; j--) {if (j >= v) {d[j] = Math.max(d[j], d[j-v] + w);}}}System.out.println(d[c]);} }
注意:

在這類求最優解的背包問題中,有的題目要求“恰好裝滿背包”時的最優解,而有的題目則并沒有要求必須裝滿。

區別這兩種問法的實現方法是在初始化的時候有所不同。

如果是要求恰好裝滿背包,那么在初始化時除了f[0]為0其它f[1..V]均設為-∞,這樣就可以保證最終得到的f[N]是一種恰好裝滿背包的最優解。

如果并沒有要求必須把背包裝滿,而是只希望價格盡量大,初始化時應該將 f[0..V]全部設為0

為什么呢?可以這樣理解:初始化的f數組事實上就是在沒有任何物品可以放入背包時的合法狀態。如果要求背包恰好裝滿,那么初始化時只有容量為0的背包可能被價值為0的物品“恰好裝滿”,其它容量的背包尚且沒有合法的解,屬于未定義的狀態;如果背包并非必須被裝滿,那么初始化時任何容量的背包都有一個合法解,即什么都不裝。


總結

以上是生活随笔為你收集整理的从背包问题优化详解动态规划思想的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。