算法學習系列(六十):區間DP

目錄

  • 引言
  • 區間合并模板
  • 一、石子合并
  • 二、環形石子合并
  • 三、能量項鏈

引言

關于這個區間 D P DP DP ,其實是有套路和模板的,題型的話也是變化不多,感覺就那幾種,只不過有些題會用到高精度或者是要記錄方案,所以整體來說還是比較容易的了,然后這種題型還是多見的為好,目前也只是會做這幾道題。其實關于藍橋杯只要你暴力都能打滿,那么國三是穩了的,如果能做對大概兩道題,那么就能拿國二,所以說搞這個 D P DP DP 也只是看能不能碰見做過類似的題目,現場解題我是不敢想了,太難的壓根做不出來,但也不能完全不學,不是特別難的還是要學,萬一出了那就是自己賺了,所以繼續加油吧,另外感覺身體累了,也是要合理的休息的!


區間合并模板

memset(f, 0x3f, sizeof f);  //先全部初始化為非法狀態 
for(int len = 1; len <= n; ++len)  // 確定r
{for(int l = 1; l + len - 1 <= n; ++l)  //確定l{int r = l + len - 1;if(l == r) f[l][r] = 0;  // 計算f[l][r]else  // 計算f[l][r]{for(int k = l; k < r; ++k) f[l][r] = min(f[l][r], f[l][k] + f[k+1][r] + ...);}}
}

一、石子合并

標簽:動態規劃、區間DP

思路:這個區間 D P DP DP 其實用之前的分析法也是可以的,一般狀態定義都是看經驗,定義一個狀態 f [ i ] [ j ] f[i][j] f[i][j] 代表合并 i ~ j i \sim j ij 區間內的石子所要花費的最小的代價,狀態計算也是跟那個 F l o y d Floyd Floyd 算法差不多,就是把這一個區間按照倒數第二步劃分,也就是把 f [ i ] [ j ] f[i][j] f[i][j] 按照分界點劃分為 f [ i ] [ k ] , f [ k + 1 ] [ j ] f[i][k],f[k+1][j] f[i][k],f[k+1][j] ,然后再進行取最小值。兩堆石子合并所花費的最小的代價,就是合并成兩堆石子各自的最小代價加上這兩堆石子總的代價,前面的也就是 f [ i ] [ k ] , f [ k + 1 ] [ j ] f[i][k],f[k+1][j] f[i][k],f[k+1][j] 了,后面的可以直接拿前綴和來做即可。那么狀態轉移方程就為 f [ l ] [ r ] = m i n ( f [ l ] [ r ] , f [ l ] [ k ] + f [ k + 1 ] [ r ] + s [ r ] ? s [ l ? 1 ] ) f[l][r] = min(f[l][r], f[l][k]+f[k+1][r] + s[r] - s[l-1]) f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]?s[l?1]) ,然后初始的狀態 f [ i ] [ i ] f[i][i] f[i][i] 的值為 0 0 0 ,然后其余的都是非法的,并且該題求的是最小值,所以初始化為正無窮即可。剩余的就按照模板即可。

題目描述:

設有 N 堆石子排成一排,其編號為 1,2,3,…,N。每堆石子有一定的質量,可以用一個整數來描述,現在要將這 N 堆石子合并成為一堆。每次只能合并相鄰的兩堆,合并的代價為這兩堆石子的質量之和,合并后與這兩堆石子相鄰的石子將和新堆相鄰,合并時由于選
擇的順序不同,合并的總代價也不相同。例如有 4 堆石子分別為 1 3 5 2, 我們可以先合并 1、2 堆,代價為 4,得到 4 5 2, 又合并 1、2 堆,代價為 9,得到 9 2 ,再合
并得到 11,總代價為 4+9+11=24;如果第二步是先合并 2、3 堆,則代價為 7,得到 4 7,最后一次合并代價為 11,總代價為 4+7+11=22。問題是:找出一種合理的方法,使總的代價最小,輸出最小代價。輸入格式
第一行一個數 N 表示石子的堆數 N。第二行 N 個數,表示每堆石子的質量(均不超過 1000)。輸出格式
輸出一個整數,表示最小代價。數據范圍
1≤N≤300
輸入樣例:
4
1 3 5 2
輸出樣例:
22

示例代碼:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 310, M = N, INF = 0x3f3f3f3f;int n, m;
int s[N], f[N][N];int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 1; i <= n; ++i) cin >> s[i], s[i] += s[i-1];memset(f, 0x3f, sizeof f);for(int len = 1; len <= n; ++len){for(int l = 1; l + len - 1 <= n; ++l){int r = l + len - 1;if(l == r) f[l][r] = 0;else{for(int k = l; k < r; ++k) f[l][r] = min(f[l][r], f[l][k] + f[k+1][r] + s[r] - s[l-1]);}}}cout << f[1][n] << endl;return 0;
}

二、環形石子合并

標簽:DP、區間DP、環形區間DP

思路:這道題跟上一道題唯一的不同就是該題的石子是環形的,不是鏈形的,解決的辦法都是在該鏈的基礎上在追加一條鏈,然后在此基礎上做區間 D P DP DP ,最后再枚舉每 n n n 堆石子找最值。為什么這樣做是正確的呢,如下圖所示,如果我們把圓圈看作石子,連邊看作是石子之間的合并,那么必然會連 n ? 1 n-1 n?1 條邊,那么肯定會如下圖所示會有一個缺口,我們把其展開就是一條長度為 n n n 的鏈了,那么我們直接枚舉這個缺口,也就是在 2 n 2n 2n 的長度下做區間為 n n n 的區間合并,最后再枚舉所有長度為 n n n 的區間的結果即可。其余的初始化等細節,詳情見代碼。
在這里插入圖片描述

題目描述:

將 n 堆石子繞圓形操場排放,現要將石子有序地合并成一堆。規定每次只能選相鄰的兩堆合并成新的一堆,并將新的一堆的石子數記做該次合并的得分。請編寫一個程序,讀入堆數 n 及每堆的石子數,并進行如下計算:選擇一種合并石子的方案,使得做 n?1 次合并得分總和最大。選擇一種合并石子的方案,使得做 n?1 次合并得分總和最小。輸入格式
第一行包含整數 n,表示共有 n 堆石子。第二行包含 n 個整數,分別表示每堆石子的數量。輸出格式
輸出共兩行:第一行為合并得分總和最小值,第二行為合并得分總和最大值。數據范圍
1≤n≤200
輸入樣例:
4
4 5 9 4
輸出樣例:
43
54

示例代碼:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 410, M = N, INF = 0x3f3f3f3f;int n, m;
int w[N], s[N];
int f[N][N], g[N][N];int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 1; i <= n; ++i){cin >> w[i];w[i+n] = w[i];}for(int i = 1; i <= n * 2; ++i) s[i] = w[i] + s[i-1];memset(f, 0x3f, sizeof f);memset(g, -0x3f, sizeof g);for(int len = 1; len <= n; ++len){for(int l = 1; l + len - 1 <= n * 2; ++l){int r = l + len - 1;if(l == r) f[l][r] = g[l][r] = 0;else{for(int k = l; k < r; ++k){f[l][r] = min(f[l][r], f[l][k] + f[k+1][r] + s[r] - s[l-1]);g[l][r] = max(g[l][r], g[l][k] + g[k+1][r] + s[r] - s[l-1]);}}}}int r1 = INF, r2 = -INF;for(int i = 1; i <= n; ++i){r1 = min(r1, f[i][i+n-1]);r2 = max(r2, g[i][i+n-1]);}cout << r1 << endl << r2 << endl;return 0;
}

三、能量項鏈

標簽:DP、區間DP、破環成鏈

思路:這道題其實跟上一道題是差不多的, 區別就是 l e n len len 最小從 2 2 2 變成 3 3 3 了,并且總的長度變為了 n + 1 n+1 n+1 ,由于題目特性,兩顆珠子根據首尾也能合并成一個珠子。所以最終的結果就是 f [ i ] [ i + n ] f[i][i+n] f[i][i+n] 里選一個,因為 l e n len len 最小是 3 3 3 ,所以 l < k < r l<k<r l<k<r ,狀態轉移方程為 ∑ k = l + 1 k = r ? 1 f [ l ] [ r ] = m a x ( f [ l ] [ r ] , f [ l ] [ k ] + f [ k ] [ r ] + w [ l ] ? w [ k ] ? w [ r ] ) \sum_{k=l+1}^{k=r-1} f[l][r] = max(f[l][r], f[l][k] + f[k][r] + w[l] * w[k] * w[r]) k=l+1k=r?1?f[l][r]=max(f[l][r],f[l][k]+f[k][r]+w[l]?w[k]?w[r]) 。其余的就是模板,細節見代碼。

題目描述:

在 Mars 星球上,每個 Mars 人都隨身佩帶著一串能量項鏈,在項鏈上有 N 顆能量珠。能量珠是一顆有頭標記與尾標記的珠子,這些標記對應著某個正整數。并且,對于相鄰的兩顆珠子,前一顆珠子的尾標記一定等于后一顆珠子的頭標記。因為只有這樣,通過吸盤(吸盤是 Mars 人吸收能量的一種器官)的作用,這兩顆珠子才能聚合成一顆珠子,同時釋放出可以被
吸盤吸收的能量。如果前一顆能量珠的頭標記為 m,尾標記為 r,后一顆能量珠的頭標記為 r,尾標記為 n,則聚合后釋放的能量為 m×r×n
(Mars 單位),
新產生的珠子的頭標記為 m,尾標記為 n。需要時,Mars 人就用吸盤夾住相鄰的兩顆珠子,通過聚合得到能量,直到項鏈上只剩下一顆珠子為止。顯然,不同的聚合順序得到的總能量是不同的,請你設計一個聚合順序,使一串項鏈釋放出的總能量最大。例如:設 N=4,4 顆珠子的頭標記與尾標記依次為 (2,3)(3,5)(5,10)(10,2)。我們用記號 ⊕ 表示兩顆珠子的聚合操作,(j⊕k) 表示第 j,k 兩顆珠子聚合后所釋放的能量。則第 4、1 兩顆珠子聚合后釋放的能量為:(4⊕1)=10×2×3=60。這一串項鏈可以得到最優值的一個聚合順序所釋放的總能量為 ((4⊕1)⊕2)⊕3)=10×2×3+10×3×5+10×5×10=710。輸入格式
輸入的第一行是一個正整數 N,表示項鏈上珠子的個數。第二行是 N 個用空格隔開的正整數,所有的數均不超過 1000,第 i 個數為第 i 顆珠子的頭標記,當 i<N 時,第 i 顆珠子的尾標記
應該等于第 i+1 顆珠子的頭標記,第 N 顆珠子的尾標記應該等于第 1 顆珠子的頭標記。至于珠子的順序,你可以這樣確定:將項鏈放到桌面上,不要出現交叉,隨意指定第一顆珠子,然后按順時針方向確定其他珠子的順序。輸出格式
輸出只有一行,是一個正整數 E,為一個最優聚合順序所釋放的總能量。數據范圍
4≤N≤100,1≤E≤2.1×109
輸入樣例:
4
2 3 5 10
輸出樣例:
710

示例代碼:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 210, M = N, INF = 0x3f3f3f3f;int n, m;
int w[N], f[N][N]; int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 1; i <= n; ++i) cin >> w[i], w[i+n] = w[i];memset(f, -0x3f, sizeof f);for(int len = 1; len <= n + 1; ++len){for(int l = 1; l + len - 1 <= n * 2; ++l){int r = l + len - 1;if(r - l + 1 < 3) f[l][r] = 0;else{for(int k = l + 1; k < r; ++k){f[l][r] = max(f[l][r], f[l][k] + f[k][r] + w[l] * w[k] * w[r]);}}}}int res = 0;for(int i = 1; i <= n; ++i){res = max(res, f[i][i+n]);}cout << res << endl;return 0;
}

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

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

相關文章

Unity編輯器如何多開同一個項目?

在聯網游戲的開發過程中&#xff0c;多開客戶端進行聯調是再常見不過的需求。但是Unity并不支持編輯器多開同一個項目&#xff0c;每次都得項目打個包(耗時2分鐘以上)&#xff0c;然后編輯器開一個進程&#xff0c;exe 再開一個&#xff0c;真的有夠XX的。o(╥﹏╥)o沒錯&#…

Hive 與 SQL 標準和主流 SQL DB 的語法區別

文章目錄 1.Hive 簡介2.Hive 與 SQL 標準和主流 SQL DB 的語法區別參考文獻 1.Hive 簡介 Hive是一種基于Hadoop的數據倉庫軟件&#xff0c;可以將結構化數據文件映射為一張數據庫表&#xff0c;并提供了類SQL查詢接口&#xff0c;使得用戶可以使用SQL類語言來查詢數據。Hive可…

7-117 死亡隧道

小毛驢要回家了,憑借著剛從老毛驢處學到的閃爍魔法,小毛驢信心滿滿地出發了。這一次它來到了另一條死亡隧道口,但是,小毛驢不知道死亡威脅隨時存在,因為它所打算穿過的這條死亡隧道即將于T秒時間后坍塌。 已知小毛驢行走的速度是每秒17米,而小毛驢擁有的閃爍法術可以使它…

返回類型后置,一個用途是為了邏輯上的體現?

大家一般都是先關心參數&#xff0c;然后最后再看返回的是什么類型。 在這里把返回類型后置&#xff0c;可能就是一種邏輯上的體現吧 fmt的一個函數。 \fmt\core.h 這個函數的意義&#xff0c;應該就是用變長參數初始化成一個format_arg_store類型的變量&#xff0c;并返回。…

Rust學習筆記(上)

前言 筆記的內容主要參考與《Rust 程序設計語言》&#xff0c;一些也參考了《通過例子學 Rust》和《Rust語言圣經》。 Rust學習筆記分為上中下&#xff0c;其它兩個地址在Rust學習筆記&#xff08;中&#xff09;和Rust學習筆記&#xff08;下&#xff09;。 編譯與運行 Ru…

成功解決No module named ‘huggingface_hub.inference._text_generation‘

成功解決No module named huggingface_hub.inference._text_generation 目錄 解決問題 解決思路 解決方法 解決問題 No module named huggingface_hub.inferen

python使用yaml文件以及元組樣式字符串使用eval的類型轉換

編程中&#xff0c;對于可變內容&#xff0c;最好是將其放入配置文件中&#xff0c;經過這段時間的學習&#xff0c;感覺使用yaml文件很方便。我的環境&#xff1a;win10&#xff0c;python3.8.10。 python使用yaml文件&#xff0c;首先要安裝庫。 pip38 install pyyaml 安裝…

AWTK 開源串口屏開發(18) - 用 C 語言自定義命令

AWTK-HMI 內置了不少模型&#xff0c;利用這些模型開發應用程序&#xff0c;不需要編寫代碼即可實現常見的應用。但是&#xff0c;有時候我們需要自定義一些命令&#xff0c;以實現一些特殊的功能。 本文檔介紹如何使用 C 語言自定義命令。 1. 實現 hmi_model_cmd_t 接口 1.1…

實現二叉樹的基本操作

博主主頁: 碼農派大星. 關注博主帶你了解更多數據結構知識 1我們先來模擬創建一個二叉樹 public class TestBinaryTreee {static class TreeNode{public char val;public TreeNode left;public TreeNode right;public TreeNode(char val) {this.val val;}}public TreeNode …

交叉編譯u-boot,qemu啟動測試

交叉編譯u-boot 1 配置交叉編譯工具鏈&#xff1a; 下載地址 https://releases.linaro.org/components/toolchain/binaries/ ### CROSS-COMPILE export AARCH64_LINUX_GNU_TOOLS/media/wmx/cross_compile_tools/aarch64-linux-gun/gcc-x86_64_aarch64-linux-gnu/bin export …

linux 安裝 mangodb 并設置服務開機自啟

1、下載 wget http://mosquitto.org/files/source/mosquitto-1.6.8.tar.gz 2、解壓 tar -zxvf mosquitto-1.6.8.tar.gz 3、編譯安裝cd mosquitto-1.6.8 make sudo make install4、在當前目錄。進入mosquitto服務文件存放的文件夾 cd service/systemd可以看到3個文件 點擊read…

【C/C++】設計模式——工廠模式:簡單工廠、工廠方法、抽象工廠

創作不易&#xff0c;本篇文章如果幫助到了你&#xff0c;還請點贊 關注支持一下?>&#x16966;<)!! 主頁專欄有更多知識&#xff0c;如有疑問歡迎大家指正討論&#xff0c;共同進步&#xff01; &#x1f525;c系列專欄&#xff1a;C/C零基礎到精通 &#x1f525; 給大…

二.基礎篇: 面向對象進階

1. 基礎篇語法篇&#xff1a;一.基礎篇&#xff1a;基礎語法-CSDN博客 面向對象進階 本章主要學習內容&#xff1a; static繼承包&#xff0c;final&#xff0c;權限修飾符&#xff0c;代碼塊抽象類接口多態內部類 1. static static翻譯過來就是靜態的意思static表示靜態&am…

AI語音模型PaddleSpeech踩坑(安裝)指南

PaddleSpeech簡介 PaddleSpeech 是基于飛槳 PaddlePaddle 的語音方向的開源模型庫&#xff0c;用于語音和音頻中的各種關鍵任務的開發&#xff0c;包含大量基于深度學習前沿和有影響力的模型。 PaddleSpeech安裝步驟 提示&#xff1a;要找到一個合適的PaddleSpeech版本與pad…

STM32開發學習——使用 Cortex-M3M4M7 故障異常原因與定位

STM32開發學習——使用 Cortex-M3/M4/M7 故障異常原因與定位 文章目錄 STM32開發學習——使用 Cortex-M3/M4/M7 故障異常原因與定位文檔說明&#xff1a;官方參考文檔線上鏈接&#xff08;可在線閱讀與下載&#xff09;&#xff1a;故障異常處理程序HardFault優先級升級說明故障…

java項目之相親網站的設計與實現源碼(springboot+mysql+vue)

風定落花生&#xff0c;歌聲逐流水&#xff0c;大家好我是風歌&#xff0c;混跡在java圈的辛苦碼農。今天要和大家聊的是一款基于springboot的相親網站的設計與實現。項目源碼以及部署相關請聯系風歌&#xff0c;文末附上聯系信息 。 項目簡介&#xff1a; 相親網站的設計與實…

連升三級!openGauss單機版從2.1.0經停3.0.0升級至5.0.0

前言 如前文所述&#xff0c;我們的小demo項目起初安裝了openGauss的2.1.0版本&#xff0c;由于2.1.0不是長期維護&#xff08;LTS&#xff09;版本&#xff0c;所以要升級到5.0.0LTS。考慮到雖然是DEMO項目&#xff0c;但也有些體驗用戶&#xff0c;所以為了保障業務連續性&a…

2023版brupsuite專業破解安裝

安裝教程&#xff0c;分兩部分&#xff1a; 1、安裝java環境、參考鏈接JAVA安裝配置----最詳細的教程&#xff08;測試木頭人&#xff09;_java安裝教程詳細-CSDN博客 2、安裝2023.4版本brupsuite&#xff1a;參考鏈接 2023最新版—Brup_Suite安裝配置----最詳細的教程&…

Java---類和對象第一節

目錄 1.面向對象初步認識 1.1什么是面向對象 1.2面向對象和面向過程的區別 2.類的定義和使用 2.1簡單認識類 2.2類的定義格式 2.3類的實例化 2.4類和對象的說明 3.this關鍵字 3.1訪問本類成員變量 3.2調用構造方法初始化成員變量 3.3this引用的特性 4.對象的構造以…

一文弄懂 Linux 系統調用函數之 exec 函數族

目錄 簡介函數原型參數說明返回值函數區別使用示例采用參數列表傳遞參數&#xff0c;以 execl 為例采用參數數組傳遞參數&#xff0c;以 execv 為例調用 PATH 下可執行文件&#xff0c;以 execlp 為例使用新的環境變量給新進程&#xff0c;以 execle 為例 更多內容 簡介 exec …