數據結構與算法學習筆記(Acwing提高課)----動態規劃·數字三角形

數據結構與算法學習筆記----動態規劃·數字三角形

@@ author: 明月清了個風
@@ first publish time: 2025.4.23

ps??終于開始提高課的題啦,借的人家的號看,以后給y總補票叭,提高課的題比之前的多很多啊哈哈哈哈,基本上每種題型都對應了難度逐步上升的幾道題,和基礎課的題相比加了一層應用,需要從題目中抽象出模型才能解題。

數字三角形的題為動態規劃的經典模型,基礎課中已經講過了,在這里。提高課的是在此基礎上的進一步延伸和應用,但原理其實沒有變。

Acwing 1015. 摘花生

Hello Kitty想摘點花生送給她喜歡的米老鼠。

她來到一片有網格狀道路的矩形花生地(如下圖),從西北角進去,東南角出來。

地里每個道路的交叉點上都有種著一株花生苗,上面有若干顆花生,經過一株花生苗就能摘走該它上面所有的花生。

Hello Kitty只能向東或向南走,不能向西或向北走。

問Hello Kitty最多能夠摘到多少顆花生。

1.gif

輸入格式

第一行是一個整數 T T T,代表一共有多少組數據。

接下來是 T T T組數據。

每組數據的第一行是兩個整數,分別代表花生苗的行數 R R R和列數 C C C

每組數據的接下來 R R R行數據,從北向南依次描述每行花生苗的情況。每行數據有 C C C個整數,按從西向東的順序描述了該行每株花生苗上的花生數目 M M M

輸出格式

對每組輸入數據,輸出一行,內容為Hello Kitty能摘到得最多的花生顆數。

數據范圍

1 ≤ T ≤ 100 1 \le T \le 100 1T100

1 ≤ R , C ≤ 100 1 \le R,C \le 100 1R,C100

0 ≤ M ≤ 1000 0 \le M \le 1000 0M1000

思路

對于動態規劃而言,和基礎課一樣,考慮狀態表示和狀態轉移。

對于狀態表示,使用f[i][j],表示的集合是所有從(1, 1)走到(i, j)的路線,而要求的屬性是這個集合中的最大值。

對于狀態轉移或者說狀態計算,就是將上述集合進行劃分,找出其子集遞歸求解。而狀態劃分的很重要的一種方法就是根據最后一步操作進行劃分,也就是f[i][j]是怎么來的這一步。在這一題中,f[i][j]可以是從上面下來,也可以是從左邊過來,因此可以劃分為兩個子集f[i][j - 1]f[i - 1][j]。需要注意的是,對于集合的劃分,最重要的兩個原則是不重不漏,其中不漏是任何情況都需要滿足的,因為每種方案都需要考慮,而不重在求最大值或最小值時可以不滿足,因為重復的計算并不會提高集合中的最值。

在上面已經將集合f[i][j]劃分為兩個集合f[i - 1][j]f[i][j - 1],那么求f[i][j]的最大值就是求這兩個子集的最大值再加上最后一步的權值即可。

代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 110;int T;
int n, m;
int a[N][N];
int f[N][N];int main()
{cin >> T;while(T --){cin >> n >> m;for(int i = 1; i <= n; i ++)for(int j = 1; j <= m; j ++)cin >> a[i][j];for(int i = 1; i <= n; i ++)for(int j = 1; j <= m; j ++)f[i][j] = max(f[i - 1][j], f[i][j - 1]) + a[i][j];cout << f[n][m] << endl;}return 0;
}

Acwing 1018. 最低通行費

一個商人穿過一個 N × N N \times N N×N的正方形的網格,去參加一個非常重要的商務活動。他要從網格的左上角進,右下角出。每穿越中間1個小方格,都要花費1個單位時間。商人必須在 2 N ? 1 2N - 1 2N?1個單位時間穿越出去。而在經過中間的每個小方格時,都需要繳納一定的費用。
這個商人期望在規定時間內用最少費用穿越出去。請問至少需要多少費用?
注意:不能對角穿越各個小方格(即,只能向上下左右四個方向移動且不能離開網格)。

輸入格式

第一行是一個整數 T T T,表示正方形的寬度 N N N

后面 N N N行,每行 N N N個不大于 100 100 100的整數,為網格上每個小方格的費用。

輸出格式

輸出一個整數,表示至少需要的費用。

數據范圍

1 ≤ N ≤ 100 1 \le N \le 100 1N100

思路

其實還是和數字三角形一樣的模型,只是多了個迷惑的地方,給了步驟限制為 2 N ? 1 2N - 1 2N?1,但是可以發現只要不回頭走就行。因此思路和代碼都是和上面一樣的。

需要注意的地方時,這一題求的集合的屬性是最小值,因此需要對邊界的地方進行特判和初始化。

代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 110, inf = 1e9;int n;
int f[N][N];
int a[N][N];int main()
{cin >> n;for(int i = 1; i <= n; i ++)for(int j = 1; j <= n; j ++)cin >> a[i][j];for(int i = 1; i <= n; i ++)for(int j = 1; j <= n; j ++){if(i == 1 && j == 1) f[i][j] = a[i][j];else{f[i][j] = inf;if(i > 1) f[i][j] = min(f[i][j], f[i - 1][j] + a[i][j]);if(j > 1) f[i][j] = min(f[i][j], f[i][j - 1] + a[i][j]);}}cout << f[n][n] << endl;return 0;
}

Acwing 1027. 方格取數

設有N*N的方格圖( N ≤ 10 N \le 10 N10),我們將其中的某些方格中填入正整數,而其他的方格中則放入數字0。
某人從圖的左上角的 A A A ( 1 , 1 ) (1, 1) (1,1)出發,可以向下行走,也可以向右走,直到到達右下角的B點 ( N , N ) (N, N) (N,N)。在走過的路上,他可以取走方格中的數(取走后的方格中將變為數字0)。
此人從 A A A點到 B B B點共走兩次,試找出2條這樣的路徑,使得取得的數之和為最大。

輸入格式

第一行是一個整數 N N N,表示 N × N N \times N N×N的方格圖。

接下來每行有三個整數,第一個為行號數,第二個為列號數,第三個為在該行、該列上所放的數。

一行以"0 ,0 ,0"表示結束。

輸出格式

給出一個整數,表示兩條路徑上取得的最大的和。

數據范圍

$ N \le 10$

思路

這一題的變化是要走兩次。對于上面兩題而言都只需要計算一個路徑,而走兩次最大的變化就是同一個數只能被拿走一次。

首先思考是兩條路線一起走還是兩條路線先后走,因為每個數只能拿一次,因此兩條路線是完全獨立的兩條線,先走后走并不影響總和。可以直接對上面的狀態表示進行推廣,使用f[i1][j1][i2][j2]表示第一條路線走到了a[i1][j1],第二條路線走到了a[i2][j2]的集合。

然后就是如何不重復走到同一個格子,因為不能回頭走,所以如果兩條線走到了同一個格子,那么肯定有 i 1 + j 1 = i 2 + j 2 i_1 + j_1 = i_2 + j_2 i1?+j1?=i2?+j2?

因此就有了下面的優化,上面這個狀態表示是四維的,雖然數據范圍很小,但是仍有優化空間,考慮到要對每個格子的坐標的和作比較,因此使用f[k][i1][i2]進行表示,其中k表示橫縱坐標的和,那么就有j1 = k - i1j2 = k - i2,當i1 == i2時,可能出現兩條路線重合。

對于狀態劃分來說,和之前的題目一樣,使用最后一步進行劃分,只是這里會有兩條路線。因此可以根據第一條路線向右或向下,第二條路線向右或向下分為四類:下下,下右,右下,右右。

以下下的組合為例說明狀態計算方法:

  • 對于下下的組合來說,兩條路線都是向下走到了最新的一步,因此是分別從a[i1][j1 - 1]a[i2][j2 - 1]走到了最新位置,這兩個地方的狀態可以由 f [ k ? 1 ] [ i 1 ] [ i 2 ] f[k - 1][i1][i2] f[k?1][i1][i2]表示,然后判斷一下是否重合即可,重合的話那就只加上一個a[i1][j1]即可,不重合就要同時加上a[i1][j1]a[i2][j2]

代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 20;int n;
int f[N * 2][N][N];
int w[N][N];int main()
{cin >> n;int a, b, c;while(cin >> a >> b >> c, a || b || c) w[a][b] = c;for(int k = 2; k <= n + n; k ++)for(int i1 = 1; i1 <= n; i1 ++)for(int i2 = 1; i2 <= n; i2 ++){int j1 = k - i1, j2 = k - i2;if(j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n){int t = w[i1][j1];if(i1 != i2) t += w[i2][j2];int &x = f[k][i1][i2];x = max(x, f[k - 1][i1- 1][i2 - 1] + t);x = max(x, f[k - 1][i1 - 1][i2] + t);x = max(x, f[k - 1][i1][i2 - 1] + t);x = max(x, f[k - 1][i1][i2] + t);}}cout << f[n + n][n][n] << endl;return 0;
}

Acwing 275. 傳紙條

小淵和小軒是好朋友也是同班同學,他們在一起總有談不完的話題。

一次素質拓展活動中,班上同學安排坐成一個 m m m n n n列的矩陣,而小淵和小軒被安排在矩陣對角線的兩端,因此,他們就無法直接交談了。

幸運的是,他們可以通過傳紙條來進行交流。

紙條要經由許多同學傳到對方手里,小淵坐在矩陣的左上角,坐標 ( 1 , 1 ) (1, 1) (1,1),小軒坐在矩陣的右下角,坐標 ( m , n ) (m, n) (m,n)

從小淵傳到小軒的紙條只可以向下或者向右傳遞,從小軒傳給小淵的紙條只可以向上或者向左傳遞。

在活動進行中,小淵希望給小軒傳遞一張紙條,同時希望小軒給他回復。

班里每個同學都可以幫他們傳遞,但只會幫他們一次,也就是說如果此人在小淵遞給小軒紙條的時候幫忙,那么在小軒遞給小淵的時候就不會再幫忙,反之亦然。

還有一件事情需要注意,全班每個同學愿意幫忙的好感度有高有低(注意:小淵和小軒的好心程度沒有定義,輸入時用 0 0 0表示),可以用一個 0 ~ 100 0 \sim 100 0100的自然數來表示,數越大表示越好心。

小淵和小軒希望盡可能找好心程度高的同學來幫忙傳紙條,即找到來回兩條傳遞路徑,使得這兩條路徑上同學的好心程度之和最大。

現在,請你幫助小淵和小軒找到這樣的兩條路徑。

輸入格式

第一行有 2 2 2個用空格隔開的整數 m m m n n n,表示學生矩陣有 m m m n n n列。

接下來 m m m行是一個 m × n m \times n m×n的矩陣,矩陣中第 i i i j j j列的整數表示坐在第 i i i j j j列的學生的好心程度,每行的 n n n個整數之間用空格隔開。

輸出格式

輸出一個整數,表示來回兩條路上參與傳遞紙條的學生的好心程度之和的最大值。

數據范圍

1 ≤ n , m ≤ 50 1 \le n, m \le 50 1n,m50

思路

這一題與上一題的區別是同一個格子不能走第二次,在上一題中,如果走到了重合的格子會少加一次權重,而這里要求是不能走第二次,其實也很好解決,也就是要證明有兩條不相交的路線具有最大的好心程度之和。

首先要解決的是兩條路線相交的問題,如果存在兩條相交的路線,如下圖所示,從A到B的兩條路線中有兩個交點C與D。

圖1

因為經過的格子的權重是確定的,因此可以對兩條路線上的部分片段進行交換,變換后入下圖:

在這里插入圖片描述

因此得證相交的路線可以通過路線的變形使其變成等效但僅有相交點而不相錯的情況。

根據題意,同一個點不能走第二次,因此考慮如何處理相交點 C C C D D D。通過觀察上圖可以發現,對于重合點C來講,該路線可以轉化為下圖所示經過點E的路線,且該路線的好心程度之和一定優于原路線(將重合點C權重清零后第二次不再計算)

在這里插入圖片描述

根據上一題的代碼可以發現,其實當走到同一點時,我們只會添加一次權重,因此這里的值一定會比經過點E的路線值小,也就是題目所限制的非法路線算出來的值一定小于最優解合法路的值,因此上一題的代碼中不必為了這一題進行修改,代碼稍有變動。

代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 60;int n, m;
int f[N * 2][N][N];
int w[N][N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++)for(int j = 1; j <= m; j ++)cin >> w[i][j];for(int k = 2; k <= n + m; k ++)for(int i1 = 1; i1 <= n; i1 ++)for(int i2 = 1; i2 <= n; i2 ++){int j1 = k - i1, j2 = k - i2;if(j1 >= 1 && j1 <= m && j2 >= 1 && j2 <= m){int t = w[i1][j1];if(i1 != i2) t += w[i2][j2];int &x = f[k][i1][i2];x = max(x, f[k - 1][i1- 1][i2 - 1] + t);x = max(x, f[k - 1][i1 - 1][i2] + t);x = max(x, f[k - 1][i1][i2 - 1] + t);x = max(x, f[k - 1][i1][i2] + t);}}cout << f[n + m][n][n] << endl;return 0;
}

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

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

相關文章

阿里巴巴安全工程師面試題:BAS

阿里巴巴新發布了針對應屆生的安全工程師招聘崗位&#xff0c;崗位要求&#xff1a; 研究新型前沿攻防技術&#xff0c;驗證正向和防御安全產品能力的有效性&#xff0c;挖掘其規則或引擎漏洞&#xff0c;并利用BAS&#xff08;Breach and Attack Simulation&#xff09;建立自…

【正則表達式】正則表達式使用總結

正則表達式除了匹配普通字符外,還可以匹配特殊字符,這些特殊字符被稱為“元字符”。? 特殊字符(元字符) ?限定符?:用于指定正則表達式中某個組件的出現次數。常見的限定符包括: *:0次或多次 +:1次或多次 ?:0次或1次 {n}:恰好n次…

數據庫對象與權限管理-Oracle數據字典詳解

1. 數據字典概念講解 Oracle數據字典是數據庫的核心組件&#xff0c;它存儲了關于數據庫結構、用戶信息、權限設置和系統性能等重要的元數據信息。這些信息對于數據庫的日常管理和維護至關重要。數據字典在數據庫創建時自動生成&#xff0c;并隨著數據庫的運行不斷更新。 數據…

鏈表系列一>兩數相加

目錄 題目&#xff1a;解析&#xff1a;方法&#xff1a;代碼&#xff1a;鏈表常用技巧&#xff1a; 題目&#xff1a; 鏈接: link 解析&#xff1a; 方法&#xff1a; 代碼&#xff1a; /*** Definition for singly-linked list.* public class ListNode {* int val;* …

FreeRTOS深度解析:隊列集(Queue Sets)的原理與應用

FreeRTOS深度解析&#xff1a;隊列集&#xff08;Queue Sets&#xff09;的原理與應用 什么是隊列集&#xff1f; 在FreeRTOS中&#xff0c;隊列集&#xff08;Queue Sets&#xff0c;英文名xQueueSet&#xff09;是一種強大的數據結構&#xff0c;用于高效管理多個隊列。它的…

QT creater和vs2017文件路徑問題

1. \\雙反斜杠&#xff0c;傳統寫法&#xff0c;需轉義 在 C/C 字符串中&#xff0c;\ 具有特殊含義&#xff0c;例如&#xff1a; \n 表示換行 \t 表示制表符 \" 表示雙引號 如果要表示一個真正的反斜杠&#xff0c;必須寫成 \\&#xff0c;否則編譯器會將其解釋為轉…

對流對象的理解

在c里&#xff0c;“流”可以理解為數據傳輸與操作的“介質”。 從輸入輸出角度來看&#xff0c;有輸入流&#xff08;比如cin&#xff09;和輸出流&#xff08;cout&#xff09;。對于輸入流&#xff0c;數據通過它從外部設備&#xff08;例如鍵盤&#xff09;“流入”程序內…

Visium HD多樣本拼片拆分

Visium HD實驗的時候一個捕獲區域內可以包含多個樣本拼片&#xff08;例如多個組織切片或不同樣本的排列&#xff09;是常見的實驗設計&#xff0c;多樣本拼片能夠提升實驗效率&#xff0c;單張玻片處理多個樣本&#xff0c;降低試劑和測序成本&#xff0c;后續分析的時候只需要…

進程(Process)詳解

進程&#xff08;Process&#xff09;詳解 一、基本定義 ?概念? 進程是計算機中程序的一次動態執行實例&#xff0c;包含程序代碼、數據及運行狀態&#xff0c;是操作系統進行資源分配和調度的基本單位?。與靜態的“程序”不同&#xff0c;進程是動態實體&#xff0c;隨程…

畢業論文超清pdf帶標簽導出

Word直接導出的pdf不夠清晰&#xff0c;使用打印導出的pdf又不帶書簽以及目錄跳轉功能這一問題&#xff0c;查閱網上資料使用Adobe DC似乎能夠解決但是下載安裝比較麻煩&#xff0c;于是寫了python程序解決該問題。 解決思路&#xff1a; 使用python腳本對兩個pdf文件進行合并…

NOIP2012提高組.同余方程

目錄 題目算法標簽: 數論, 擴展歐幾里得算法思路代碼 題目 203. 同余方程 算法標簽: 數論, 擴展歐幾里得算法 思路 簡單的擴展歐幾里得算法應用題, 擴展歐幾里得算法可以直接計算同余方程的通解, 因為求得是最小正整數解, 因此需要取模轉換為正整數 a x b y ≡ 1 ax by …

C++學習-入門到精通-【0】計算機和C++簡介

C學習-入門到精通-[0]計算機和C簡介 計算機和C簡介 C學習-入門到精通-[0]計算機和C簡介一、計算機的組成二、硬件和軟件三、數據的層次結構四、機器語言、匯編語言和高級語言五、C標準庫六、面向對象技術 一、計算機的組成 計算機是由多個不同功能的邏輯單元組成的&#xff1a…

macOS 系統設置息屏情況下,PHP等后臺腳本繼續執行

在 macOS 系統下&#xff0c;當屏幕息屏或合上蓋子時&#xff0c;后臺腳本程序是否會繼續運行&#xff0c;主要取決于以下幾個因素&#xff1a; 1. 系統睡眠狀態的影響 默認情況&#xff1a;合蓋/息屏后&#xff0c;Mac 會進入「睡眠模式」&#xff08;部分硬件休眠&#xff…

SpringBoot集成ActiveMQ異常處理機制:若未捕獲異常,消息會被重新投遞

一、問題描述 SpringBoot項目集成AvtiveMQ&#xff0c;作為消息消費者。如果在消費消息的方法中&#xff0c;拋出異常&#xff0c;會產生什么效果&#xff1f; 二、ActiveMQ異常處理機制&#xff08;AI問答僅供參考&#xff09; 在Spring Boot項目集成ActiveMQ作為消息消費者…

【Java學習筆記】random的使用

random使用方法 使用說明&#xff1a;返回的是(0<n<1)這個范圍中的任意帶正號的double值 代碼實例 public class helloworld{public static void main(String[] args){System.out.println(Math.random());} }生成0-100中的任意數代碼示例 public class Main {public …

(三)垂直分庫架構、分布式數據庫

文章目錄 垂直分庫架構/分布式數據庫什么是垂直分庫架構架構模型優缺點優點缺點 技術案例分布式數據庫架構模型優缺點優點缺點 技術案例 垂直分庫架構/分布式數據庫 什么是垂直分庫架構 根據業務的模塊劃分&#xff0c; 將不同業務的數據放到不同的數據庫中。 比如一個電子商城…

數據結構線性表的順序存儲結構

線性表是由零個或多個數據元素組成的有序序列。 特點&#xff1a; 數據元素間是有順序的&#xff1b; 數據元素的個數是有限的&#xff1b; 一般來說&#xff0c;數據元素的類型是相同的&#xff08;強類型語言&#xff09;。c/c是強類型語言&#xff0c;必須指定數據類型。…

扣子空間試用:生成五一騎行規劃+notion文章編寫

今天試用了一下扣子空間&#xff0c;正好五一快到了&#xff0c;讓它幫忙做了五一騎行規劃&#xff0c;效果不賴&#xff01; 生成五一騎行規劃 點擊前往網站查看效果 prompt 如下&#xff1a; 幫我做一個五一上海騎行規劃 要求&#xff1a; - 風景優美 - 人少 - 100km總路程…

最新得物小程序sign簽名加密,請求參數解密,響應數據解密逆向分析

點擊精選&#xff0c;出現https://app.dewu.com/api/v1/h5/index/fire/index 這個請求 直接搜索sign的話不容易定位 直接搜newAdvForH5就一個&#xff0c;進去再搜sign&#xff0c;打上斷點 可以看到t.params就是沒有sign的請求參數&#xff0c; 經過Object(a.default)該函數…

在C#串口通信中,一發一收的場景,如何處理不同功能碼的幀數據比較合理,代碼結構好

在 C# 串口通信的一發一收場景里&#xff0c;處理不同功能碼的幀數據可采用以下合理的代碼結構&#xff0c;它能讓代碼更具可讀性、可維護性和可擴展性。 實現思路 定義幀結構&#xff1a;創建一個類來表示通信幀&#xff0c;其中包含功能碼、數據等信息。功能碼處理邏輯&…