這裡單獨寫一下動態規劃專題,藍橋杯當中一定會出一道動態規劃的題目所以稍微彙總一下。
(源於藍橋杯2020屆一道題目)
1.某市市長獲得了若干批口罩,每一批口罩的數目如下:(如果你把以下文字複製到文字檔案中,請務必檢查複製的內容是否與文件中的一致。在試題目錄下有乙個檔案 mask.txt,內容與下面的文字相同)
9090400,8499400,5926800,8547000,4958200,4422600,5751200,4175600,6309600
,5865200,6604400,4635000,10663400,8087200,4554000
現在市長要把口罩分配給市內的 2 所醫院。由於物流限制,每一批口罩只能全部分配給其中一家醫院。市長希望2 所醫院獲得的口罩總數之差越小越好。請你計算這個差最小是多少?
首先求最值那麼一般思路都是往dp方向上去靠,同時這道題又是最經典動態規劃中的揹包問題,首先先要判斷數是否可重用,不可重用就是子集揹包問題,可重用就是完全揹包問題,這兩者之間有微妙的差別
藍橋杯演算法模板常用套路
ps:就是這其中內層迴圈的差別,該題題解如下,j應該是從後往前反向遍歷,因為每個物品(或者說數字)只能用一次,以免之前的結果影響其他的結果。最值問題一般是(dp動態規劃,那麼這道題是一道變形的揹包問題)
對於揹包容量為sum/2的有i批個口罩,口罩數為nums[i],那麼最大差值是多少
static
int[
] dp =
newint
[98090000];
static
int sum =0;
static
int[
] nums =
;public
static
void
main
(string[
] args)
system.out.
println
(sum)
;int v = sum /2;
for(
int i =
1; i < nums.length; i++)}
system.out.
println
(dp[v]);
system.out.
println
(sum - dp[v]*2
);}
2.再來看一道題目,輸入乙個只包含正整數的非空陣列nums,請你寫乙個演算法,判斷這個陣列是否可以背分割成兩個子串,使得兩個子集的元素和相等。
輸入nums[1,5,11,5],演算法返回true,因為nums可以分割成[1,5,5]和[11]
輸入nums[1,3,2,5],演算法返回false,因為nums無論如何都不能分割成兩個和相等的子集
可以把問題轉換成揹包問題,對於容量為sum/2的揹包和i個物品,其他重量為nums[i],是否存在一種裝法,恰好將揹包裝滿,能轉化為揹包問題就直接套用模板
static
int sum =0;
static
int[
] nums =
;static
boolean
dp =
newboolean[22
];public
static
void
main
(string[
] args)
public
static
boolean
canpartition
(int
nums)
if(sum %2!=
0)return
false
;int v = sum /2;
for(
int i =
1; i < nums.length; i++)}
return dp[v]
;}
3.那麼接下來我們看一道完全揹包問題,零錢兌換,給定不同面額的硬幣coins和乙個總金額amount,寫乙個函式來計算可以湊成總金額的硬幣組合數。假設每一種面額的硬幣有無限個。
比如輸入amount = 5,coins = [1,2,5],演算法應該返回4,因為有如下四種方式可以湊出目標金額:
5 = 5
5 = 2 + 2 + 1
5 = 2 + 1 + 1 + 1
5 = 1 + 1 + 1 + 1 + 1
我們可以把這個問題轉換成揹包問題,對於揹包容量為5的揹包有i個硬幣,硬幣的大小為coins[i],數量為無限個。(無限個意味著可以重複使用硬幣,參照揹包問題和完全揹包的套路模板,其實區別就是在此是否可重用),對於內層迴圈就是揹包容量進行迴圈,前者是從z後往前(防止重複使用影響節後),後者是從前往後迴圈。
public
class
bagdemo1test
; system.out.
println
(moneychange
(amount, coins));
}public
static
intmoneychange
(int amount,
int[
] coins)
}return dp[amount];}
}
來做三道連續的dp陣列題目來鞏固一下動態規劃
4.leetcode打家劫舍題目1
ps:這道題要求求最值,首先先找狀態和選擇,狀態很明顯就是可選擇的房屋,那麼選擇就是選擇該房子或者不選擇該房子,根據套路模板
for
(狀態1 in 狀態1 的所有取值)
for(狀態2 in 狀態2 的所有取值)
dp[i]
= 計算(選擇1,選擇2
)//關鍵就是在於對dp陣列的定義並且這個計算,指的是要對於題目而言dp陣列的定義來進行計算
那麼可以觀察該題目,因為題目的dp[i]只與dp[i + 1]和dp[i + 2]的值有關,所以可以將空間複雜度降為o(1),如下所示.
public
class
demo2
return dp_i;
}}
5.leetcode打家劫舍2
這道題和上一題類似,但是房屋是環形的,其實可以就只有三種情況
1.要麼第乙個和最後乙個都不取
2.第乙個取,最後乙個不取
3.最後乙個取,第乙個不取
後兩者已經將第一種情況涵括,將後兩者的情況進行求最值即可。
public
class
demo3
/* * 其實和上一道題差不多,就是要對引數進行更改就行
* */
public
introbrange
(int
nums,
int end,
int start)
return dp_i;
}}
6.leetcode打家劫舍3
那麼這道題涵蓋遞迴和動態規劃,首先樹形結構一定要考慮遞迴,並且對於遞迴樹,一定要對其進行剪枝,用乙個hashmapmemo備忘錄取存放值,如果備忘錄中存在值就可以取出。
public
class
demo4
}
總結:那麼我們來**一下動態規劃和回溯演算法之間的關係
先說一下回溯演算法,dfs和回溯演算法對於這兩者而言,我個人也是模稜兩可,而對於套路模板中,我所發現的動態規劃和dfs之間有相似之處就是,有時候要區別對數字是否可重用有一些相應的操作。
藍橋杯刷題
題目 問題描述 給定圓的半徑r,求圓的面積。輸入格式 輸入包含乙個整數r,表示圓的半徑。輸出格式 輸出一行,包含乙個實數,四捨五入保留小數點後7位,表示圓的面積。說明 在本題中,輸入是乙個整數,但是輸出是乙個實數。對於實數輸出的問題,請一定看清楚實數輸出的要求,比如本題中要求保留小數點後7位,則你的...
藍橋杯刷題
題目 問題描述 求1 2 3 n的值。輸入格式 輸入包括乙個整數n。輸出格式 輸出一行,包括乙個整數,表示1 2 3 n的值。樣例輸入 4樣例輸出 10樣例輸入 100說明 有一些試題會給出多組樣例輸入輸出以幫助你更好的做題。一般在提交之前所有這些樣例都需要測試通過才行,但這不代表這幾組樣例資料都正...
藍橋杯刷題
題目 問題描述 給定n個十六進製制正整數,輸出它們對應的八進位制數。輸入格式 輸入的第一行為乙個正整數n 1 n 10 接下來n行,每行乙個由09 大寫字母af組成的字串,表示要轉換的十六進製制正整數,每個十六進製制數長度不超過100000。輸出格式 輸出n行,每行為輸入對應的八進位制正整數。注意 ...