解決動態規劃問題4步曲

概述

  1. (確定狀態)確定問題狀態
    • 提煉最后一步
    • 子問題轉化
  2. (求得方程)轉移方程,把問題方程化
  3. (設初置界)按照實際邏輯設置初始條件和邊界情況
  4. (確序再解)確定計算順序并求解

一個案例:最少硬幣組合

你打算買一本27元的書,你現有三種硬幣,分別面值2元,5元和7元,每種硬幣都充足。請問如何用個數最少的硬幣組合正好付清?

正常人第一反應思路:

最少硬幣組合?

  • 優先使用大面值硬幣 —— 7+7+7+5=26,不符合求解目標27元。
  • 換種組合 —— 7+7+7+2+2+2=27,總共用了6枚硬幣正好27元。
  • 實際正確答案 —— 7+5+5+5+5=27,才用了5枚硬幣。

所以這里貪心算法是并不適用。

題目中關鍵詞“最少的”,這是用到“動態規劃”的味道

解決動態規劃問題4步

第一步,確定問題狀態

動態規劃問題求解需要先開一個數組,并確定數組的每個元素f[i]代表什么,這就是確定這個問題的狀態。這類似于解數學題中,設定x,y,z代表什么。

A、確定狀態首先提取“最后一步”

最優策略必定是K枚硬幣a1, a2, …, aK面值加起來是27。

找出不影響最優策略的最后一個獨立角色,這道問題中,那枚最后的硬幣aK就是最后一步。把aK提取出來,硬幣aK之前的所有硬幣面值加總是27-aK。因為總體求最硬幣數量最少策略,所以拼出27-aK的硬幣數也一定最少(重要設定)。

在這里插入圖片描述

B、轉化子問題

最后一步aK提出來之后,我們只要求出“最少用多少枚硬幣可以拼出27- aK”就可以了。

這種與原問題內核一致,但是規模變小的問題,叫做子問題

為簡化定義,我們設狀態f(X)=最少用多少枚硬幣拼出總面值X

我們目前還不知道最后的硬幣aK面額多少,但它的面額一定只可能是{2, 5, 7}之一。

  • 如果aK是2,f(27)應該是f(27-2) + 1(加上最后這一枚面值2的硬幣)
  • 如果aK是5,f(27)應該是f(27-5) + 1(加上最后這一枚面值5的硬幣)
  • 如果aK是7,f(27)應該是f(27-7) + 1(加上最后這一枚面值7的硬幣)

除此以外,沒有其他的可能了。至此,通過找到原問題最后一步,并將其轉化為子問題。

為求面值總額27的最小的硬幣組合數的狀態就形成了,用以下函數表示:

f(27) = min{f(27-2)+1, f(27-5)+1, f(27-7)+1}

在這里插入圖片描述

第二步,轉移方程,把問題方程化

f[X] = min{f[X-2]+1, f[X-5]+1, f[X-7]+1}

動態規劃都是要開數組,所以上面式子改用方括號表示。實際求解動態規劃類問題,正確列出轉移方程正確基本上就解決一半了。

遞歸的解法:

// f(X)返回最少用多少枚硬幣拼出X
int f(int X) {// 0元錢只要0枚硬幣if (X == 0) return 0;// 初始化用無窮大(int res = Integer.MAX_VALUE;// 最后一枚硬幣是2元if (X >= 2) {res = Math.min(f(X – 2) + 1, res);}// 最后一枚硬幣是5元if (X >= 5) {res =  Math.min(f(X – 5) + 1, res);}// 最后一枚硬幣是7元if (X >= 7) {      res =  Math.min(f(X – 7) + 1, res);}return res;
}

執行圖如下:

在這里插入圖片描述

要算f(27),就要遞歸f(25)、f(22)、f(20),然后下邊依次遞歸。

在這里插入圖片描述

問題明顯:重復遞歸太多

這是求f(27),等待時間還可以接受。如果求f(100)呢?

求總體最值,可優先考慮動態規劃,不要貿然去遞歸。

第三步,按照實際邏輯設置邊界情況和初始條件。

如果不按照實際邏輯設置邊界情況和初始條件,即使轉移方程正確也大概率無法跑通代碼。

f[X] = min{f[X-2]+1, f[X-5]+1, f[X-7]+1}的邊界情況是[x-2][x-5][x-7]不能小于0(硬幣面值為正),也不能高于27。

故對邊界情況設定如下

如果硬幣面值不能組合出Y,就定義f[Y]=正無窮。例如,f[-1] = f[-2] = … = 正無窮f[1] = min{f[-1]+1, f[-4]+1,f[-6]+1} = 正無窮特殊情況:本題的F[0]對應的情況為F[-2]、F[-5]、F[-7],按照上文的邊界情況設定結果是正無窮,但是實際上F[0]的結果是存在的(即使用0個硬幣的情況下),F[0]=0

可是按照我們剛剛的設定,F[0]=F[0-2]+1= F[-2]+1=正無窮豈不是矛盾?這種用轉移方程無法計算,但是又實際存在的情況,就必須通過手動定義。這里手動強制定義初始條件為:F[0]=0

而從0之后的數值是沒矛盾的,比如F[1]= F[1-2]+1= F[-1]+1=正無窮(正無窮加任何數結果還是正無窮),F[2] = F[2-2]+1 = F[0]+1=1

第四步,確定計算順序并計算求解

那么開始計算時,是從F[1]F[2]開始呢?還是從F[27]F[26]開始呢?

判斷計算順序正確與否的原則是:當我們要計算F[X](等式左邊,如F[10])的時候,等式右邊(f[X-2]f[X-5]f[X-7]等)都是已經得到結果的狀態,這個計算順序就是OK的。

實際就是從小到大的計算方式(偶有例外的情況)。

例如我們算到F[12]的時候,發現F[11]F[10]F[9]都已經算過了,這種算法就是對的。而開始算F[27]的時候,發現F[26]還沒有算,這樣的順序就是錯的。

很顯然這樣的情況下寫一個for循環就夠了。

回到這道題,采用動態規劃的算法,每一步只嘗試三種硬幣,一共進行了27步。算法時間復雜度(即需要進行的步數)為27*3。

與遞歸相比,沒有任何重復計算

本文的題目來源:LeetCode - Medium - 322. Coin Change

代碼如下:

public class CoinChange {public int coinChange(int[] coins, int amount) {int[] f = new int[amount + 1];Arrays.fill(f, Integer.MAX_VALUE);f[0] = 0;for (int i = 1; i <= amount; i++) {//如果通過放這個硬幣能夠達到數量ifor(int coin : coins) {if (i >= coin && f[i - coin] != Integer.MAX_VALUE)// 獲得i的數量的硬幣數就可能是獲得i-A[j]重量硬幣數的方案+1// 拿這個方案數量與原本的方案數打擂臺,取最小值就行f[i] = Math.min(f[i - coin] + 1, f[i]);}}if (f[amount] == Integer.MAX_VALUE) {return -1;}return f[amount];}
}

總結

  1. 這是求最值問題,用動態規劃方式求解。(案例:最少硬幣組合)
  2. 進入求解過程,先確定問題狀態
    • 提煉最后一步(最優策略中使用的最后一枚硬幣aK
    • 子問題轉化(最少的硬幣拼出更小的面值X-aK
  3. 構建轉移方程(f[X] = min{f[X-2]+1, f[X-5]+1, f[X-7]+1}
  4. 設置初始條件和邊界情況(f[0] = 0, 如果不能拼出Y,f[Y]=正無窮
  5. 確定計算順序并計算求解(f[0], f[1], f[2],…)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445760.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445760.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445760.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

php ajax隊列,AJAX請求隊列實現

這篇文章主要為大家詳細介紹了AJAX請求隊列的實現代碼,具有一定的參考價值&#xff0c;感興趣的小伙伴們可以參考一下AJAX在使用的過程中會遇到一個問題&#xff0c;當用戶短時間內執行了多個異步請求的時候&#xff0c;如果前一個請求沒完成&#xff0c;將會被取消執行最新的一…

php Spreadsheet 導出,PhpSpreadsheet 導出Excel

/*** Excel 助手* sudo composer require phpoffice/phpspreadsheet*/namespace CommonUtil;use PhpOfficePhpSpreadsheetSpreadsheet;use PhpOfficePhpSpreadsheetWriterXlsx;use PhpOfficePhpSpreadsheetStyleAlignment;use PhpOfficePhpSpreadsheetStyleColor;class ExcelUt…

php 不同時區時間轉換,在PHP中將DateTime字符串轉換為不同的時區

好吧,我有以下代碼$from "Asia/Manila";$to "UTC";$org_time new DateTime("2012-05-15 10:50:00");$org_time $org_time->format("Y-m-d H:i:s");$conv_time NULL;$userTimezone new DateTimeZone($from);$gmtTimezone new…

php iis ajax 無效,IIS7中Ajax.AjaxMethod無效的原因及解決方法

最近做用Ajax.AjaxMethod方法的時候&#xff0c;在asp.net的服務器下一切正常&#xff0c;用iis的時候&#xff0c;js中總是cs類找不到&#xff0c;我就郁悶了&#xff0c;折騰了大半天&#xff0c;終于找到錯誤原因了。因為我發布網站用的是iis7&#xff0c;所以在web.config位…

查看oracle監聽服務器,處理Oracle 監聽文件listener.log問題

如果連接時候變得較慢 查看Oracle日志記錄&#xff0c;可能是因為此文件太大&#xff0c;超過2G&#xff0c;需要定期清理&#xff0c;(如果多用戶&#xff0c;記得用root&#xff0c;可能沒權限)查看listener.log&#xff1f;find / -name listener.log經查看&#xff0c;竟然…

oracle添加偽列,Oracle偽列 - jifengtang的個人空間 - OSCHINA - 中文開源技術交流社區...

在oracle10g和下&#xff0c;偽列包括如下內容&#xff1a;lHierarchical Query Pseudocolumns分級查詢是oracle提供的遞歸查詢語法&#xff0c;在這里不做展開。只有在分級查詢下&#xff0c;才可以使用以下偽列&#xff1a;1.CONNECT_BY_ISCYCLE Pseudocolumn2.CONNECT_BY_IS…

美國oracle球場,美國體育館考察——美國體育產業是如何盈利的?

體育是美國一項較高利潤的產業&#xff0c;其發展規模、發展水平和效益都是世界一流的。美國體育館考察&#xff0c;主要考察美國體育產業的盈利模式和體育賽事的贊助模式以及球館的運營管理&#xff0c;并對比中美體育產業的差異&#xff0c;從中獲得先進的體育產業運營思維&a…

php集成環境怎么打開,PHP集成開發環境PhpStorm快速入門指南(二):打開一個項目?...

PhpStorm是一個輕量級且便捷的PHP IDE&#xff0c;其旨在提高用戶效率&#xff0c;可深刻理解用戶的編碼&#xff0c;提供智能代碼補全&#xff0c;快速導航以及即時錯誤檢查。可隨時幫助用戶對其編碼進行調整&#xff0c;運行單元測試或者提供可視化debug功能。PhpStorm 2019.…

如何查詢oracle最近報警信息,教你怎樣用Oracle方便地查看報警日志錯誤

在網上查了幾天的資料&#xff0c;嘗試綜合清除告警日志內容及建外部表的方式來解決這一問題。一&#xff1a;備份并清除告警日志內容將每天的告警日志備份好&#xff0c;然后進行清除。1:備份報警日志在$ORACLE_HOME/SID/bdump/ 目錄下&#xff0c;按日期備份alert_ORACLE_你…

計算機分php,計算機按照處理數據的形態分類,可以分為什么?

計算機按照處理數據的形態分類&#xff0c;可以分為&#xff1a;1、數字計算機&#xff0c;是以數字形式的量值在機器內部進行運算和存儲的電子計算機&#xff1b;2、模擬計算機&#xff0c;是根據相似原理&#xff0c;用一種連續變化的模擬量作為被運算的對象的計算機&#xf…

2.oracle物理結構,oracle實驗2oracle物理結構管理

oracle實驗2oracle物理結構管理 (6頁)本資源提供全文預覽&#xff0c;點擊全文預覽即可全文預覽,如果喜歡文檔就下載吧&#xff0c;查找使用更方便哦&#xff01;9.9 積分實驗2 oracle物理存儲結構管理、實驗目的1. 掌握物理結構的創建和修改方法2. 掌握表空間的存儲參數設置方…

linux mount 查看掛載目錄,Linux下使用mount來掛載設備到目錄

一般情況下直接mount 設備路徑 目錄路徑&#xff0c;就可以了。umount 設備名&#xff0c;就可以卸載這個設備了使用lsblk -f可以查看掛載的設備&#xff0c;以及這些設備的文件系統。roottao-PC:/boot# lsblk -fNAME FSTYPE LABEL UUID MOUNTPOINTsda├─sda1├─sda2 vfat SY…

centos7是哪種版本Linux,centos7怎么查看系統版本是不是7.2 7.5 7.6

CentOS的版本號信息一般存放在配置文件當中&#xff0c;在CentOS中&#xff0c;與其版本相關的配置文件中都有centos關鍵字&#xff0c;該文件一般存放在/etc/目錄下&#xff0c;所以說我們可以直接在該文件夾下搜索相關的文件。其中存放其版本配置信息的文件為“centos-releas…

linux6.0 安裝教程,CentOS 6.0安裝步驟

1&#xff0e;安裝引導選擇安裝或升級現有系統(Install or upgrade an existing system)&#xff1a;這個選項是默認的。 選擇此選項&#xff0c;安裝到您的計算機使用CentOS的圖形安裝程序的系統。2.檢測光盤介質可以選擇skip跳過3.選擇安裝過程中的語言這里選擇chinese中文簡…

LeetCode - Easy - 14. Longest Common Prefix

Topic String Description https://leetcode.com/problems/longest-common-prefix/ Write a function to find the longest common prefix string amongst an array of strings. If there is no common prefix, return an empty string “”. Example 1: Input: strs […

linux 虛函數調用性能,C++對象布局及多態實現探索之虛函數調用

我們再看看虛成員函數的調用。類C041中含有虛成員函數&#xff0c;它的定義如下&#xff1a;struct C041{C041() : c_(0x01) {}virtual void foo() { c_ 0x02; }char c_;};執行如下代碼&#xff1a;C041 obj;PRINT_DETAIL(C041, obj)PRINT_VTABLE_ITEM(obj, 0, 0)obj.foo();C0…

netflow流量分析工具 linux,Centos5/Linux安裝Nfdump和Nfsen圖形界面分析netflow數據

Nfdump是linux下netflow數據采集分析工具&#xff0c;Nfsen是基于nfdump是web界面工具&#xff0c;服務器需先安裝web服務器和php環境。安裝rrdtool及所需組件&#xff1a;yum install perl-rrdtool rrdtool rrdtool-devel rrdutils flex byacc安裝所需perl模塊&#xff1a;yum…

linux嵌入式平臺測試,protobuf-c 在arm linux 嵌入式平臺的使用 測試

關于什么是protobuf&#xff0c;網上搜搜一大堆&#xff0c;很多人用的都還是json&#xff0c;以為json是多種語言傳輸數據是萬能的&#xff0c;看完了protobuf的實現&#xff0c;就明白了簡單高效才是王道。1、首先寫一個.proto擴展名的文件json.proto&#xff0c;內容格式如下…

Linux gitpush錯誤,linux – GIT:無法推送(奇怪的配置問題)

我正在全新安裝Linux Mint.嘗試從任何存儲庫推送時,我收到以下錯誤&#xff1a;error: Malformed value for push.default: simpleerror: Must be one of nothing,matching,tracking or current.fatal: bad config file line 8 in /home/leng/.gitconfigfatal: Could not read …

linux+shell+func,Linux shell編程筆記總結

Linux Shell學習筆記簡介Linux系統的shell作為操作系統的外殼&#xff0c;為用戶提供使用操作系統的接口。它是命令語言、命令解釋程序及程序設計語言的統稱。shell是用戶和Linux內核之間的接口程序&#xff0c;如果把Linux內核想象成一個球體的中心&#xff0c;shell就是圍繞內…