專題 四維DP

2022-05-30 17:18:08 字數 4148 閱讀 1620

題目描述

設有n×n的方格圖(n≤9),我們將其中的某些方格中填入正整數,而其他的方格中則放入數字0。如下圖所示(見樣例):

a0 0 0 0 0 0 0 0

0 0 13 0 0 6 0 0

0 0 0 0 7 0 0 0

0 0 0 14 0 0 0 0

0 21 0 0 0 4 0 0

0 0 15 0 0 0 0 0

0 14 0 0 0 0 0 0

0 0 0 0 0 0 0 0

b某人從圖的左上角的a點出發,可以向下行走,也可以向右走,直到到達右下角的b點。在走過的路上,他可以取走方格中的數(取走後的方格中將變為數字0)。

此人從a點到b點共走兩次,試找出2條這樣的路徑,使得取得的數之和為最大。

輸入格式

輸入的第一行為乙個整數nn(表示n \times nn×n的方格圖),接下來的每行有三個整數,前兩個表示位置,第三個數為該位置上所放的數。一行單獨的00表示輸入結束。

輸出格式

只需輸出乙個整數,表示22條路徑上取得的最大的和。

其實如果只走一條路徑完全可以直接二維dp出來。但是這題有乙個特殊的地方, 那就是取走的地方會變為0.這就不允許我們分別dp。在這種情況下,我們要參考資料範圍,然後發現,可以設f[i][j][p][q]表示第一條路走到了(i,j),第二條路走到了(p,q),的最大值。因為第二條路和第一條路的兩個端點是一樣的,所以可以當成從同一起點出發的兩條路了。然後轉移時就列舉兩條路分別是從上面還是左面轉移來的即可。

**:

#include#includeusing namespace std;

int s[10][10], n, f[10][10][10][10];

inline int max(int x, int y)

int main()

while (1);

for (int i = 1; i <= n; i++)

for (int j = 1; j <= n; j++)

for (int p = 1; p <= n; p++)

for (int q = 1; q <= n; q++)

cout << f[n][n][n][n] << endl;

return 0;

}

題目背景

小明過生日的時候,爸爸送給他一副烏龜棋當作禮物。

題目描述

烏龜棋的棋盤是一行n個格仔,每個格仔上乙個分數(非負整數)。棋盤第1格是唯一的起點,第n格是終點,遊戲要求玩家控制乙個烏龜棋子從起點出發走到終點。

烏龜棋中m張爬行卡片,分成4種不同的型別(m張卡片中不一定包含所有4種型別的卡片,見樣例),每種型別的卡片上分別標有1,2,3,4四個數字之一,表示使用這種卡片後,烏龜棋子將向前爬行相應的格仔數。遊戲中,玩家每次需要從所有的爬行卡片中選擇一張之前沒有使用過的爬行卡片,控制烏龜棋子前進相應的格仔數,每張卡片只能使用一次。

遊戲中,烏龜棋子自動獲得起點格仔的分數,並且在後續的爬行中每到達乙個格仔,就得到該格仔相應的分數。玩家最終遊戲得分就是烏龜棋子從起點到終點過程中到過的所有格仔的分數總和。

很明顯,用不同的爬行卡片使用順序會使得最終遊戲的得分不同,小明想要找到一種卡片使用順序使得最終遊戲得分最多。

現在,告訴你棋盤上每個格仔的分數和所有的爬行卡片,你能告訴小明,他最多能得到多少分嗎?

輸入格式

每行中兩個數之間用乙個空格隔開。

第1行2個正整數n,m,分別表示棋盤格仔數和爬行卡片數。

第2行n個非負整數,a_1,a_2,…,a_n。其中a_i表示棋盤第i個格仔上的分數。

第3行m個整數,b_1,b_2,…,b_m,表示m張爬行卡片上的數字。

輸入資料保證到達終點時剛好用光m張爬行卡片。

輸出格式

1個整數,表示小明最多能得到的分數。

至此我們已經基本上看出來了四維dp的使用前提:

二維通常不符合題意

資料範圍能承受的住

題目中的關鍵資訊往往可以關聯到四個種類的資訊。

在這道題中,卡片的數目已經限定有且只有4種了,且每種卡片的使用互相獨立,而且資料範並不大,因此我們考慮設f[i][j][p][q]表示第一種卡片用了i張,第二種卡片用了j張,第三種卡片用了p張,第四種卡片用了q張,所能得到的最大分數。因為題目保證所有卡片都用完,所以目標是f[c1][c2][c3][c4].轉移的時候直接根據用的張數就可以直接算出現在在哪乙個點。

**:

#include#include#includeusing namespace std;

int n, c, c1, c2, c3, c4, f[45][45][45][45], s[355];

inline int max(int x, int y)

int main()

f[0][0][0][0] = s[1];

if (c4 > 0) f[1][0][0][0] = s[5];

if (c3 > 0) f[0][1][0][0] = s[4];

if (c2 > 0) f[0][0][1][0] = s[3];

if (c1 > 0) f[0][0][0][1] = s[2];

for (int i = 0; i <= c4; i++)

for (int j = 0; j <= c3; j++)

for (int p = 0; p <= c2; p++)

for (int q = 0; q <= c1; q++)

cout << f[c4][c3][c2][c1] << endl;

return 0;

}

題目描述

小淵和小軒是好朋友也是同班同學,他們在一起總有談不完的話題。一次素質拓展活動中,班上同學安排做成乙個m行n列的矩陣,而小淵和小軒被安排在矩陣對角線的兩端,因此,他們就無法直接交談了。幸運的是,他們可以通過傳紙條來進行交流。紙條要經由許多同學傳到對方手裡,小淵坐在矩陣的左上角,座標(1,1),小軒坐在矩陣的右下角,座標(m,n)。從小淵傳到小軒的紙條只可以向下或者向右傳遞,從小軒傳給小淵的紙條只可以向上或者向左傳遞。

在活動進行中,小淵希望給小軒傳遞一張紙條,同時希望小軒給他回覆。班裡每個同學都可以幫他們傳遞,但只會幫他們一次,也就是說如果此人在小淵遞給小軒紙條的時候幫忙,那麼在小軒遞給小淵的時候就不會再幫忙。反之亦然。

還有一件事情需要注意,全班每個同學願意幫忙的好感度有高有低(注意:小淵和小軒的好心程度沒有定義,輸入時用0表示),可以用乙個0-100的自然數來表示,數越大表示越好心。小淵和小軒希望盡可能找好心程度高的同學來幫忙傳紙條,即找到來回兩條傳遞路徑,使得這2條路徑上同學的好心程度之和最大。現在,請你幫助小淵和小軒找到這樣的2條路徑。

輸入格式

輸入檔案,第一行有2個用空格隔開的整數m和n,表示班裡有m行n列。

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

輸出格式

輸出檔案共一行,包含乙個整數,表示來回2條路上參與傳遞紙條的學生的好心程度之和的最大值。

其實這道題因為放在了這個專題裡而變得很簡單。如果平時看到這道題,我們很可能會首先考慮二維dp,即先找出最大的一條路,再找另一條最大的路。但是這是錯誤的。因為題目要求兩條路沒有公共點,也就是說直接找到最大的一條路有可能會使得其他答案被阻斷從而出現了第一條路優但是全域性不優的結果。因此我們只能考慮四維dp。設f[i][j][p][q]表示第一條路到了(i,j),第二條路到了(p,q)的最大值,然後我們用類似第一題的做法來解決這個題就可以了。

**:

#include#include#includeusing namespace std;

int n, m, f[52][52][52][52], c[50][50];

inline int max(int x, int y)

int main()

cout << f[n][m - 1][n - 1][m] << endl;

return 0;

}

Problem D 烏龜棋 四維dp

time limit 1 sec memory limit 128 mb submit 24 solved 15 submit status web board 小明過生日的時候,爸爸送給他一副烏龜棋當作禮物。烏龜棋的棋盤是一行 n 個格仔,每個格仔上乙個分數 非負整數 棋盤第 1 格是唯一 的起點...

四維dp 方格取數

給定乙個 n times n 的方格,只能向下和向右行走,有些方格上有一些數字,其餘為 0 每個數字只能取一次,乙個人從左上角走到右下角兩次能夠取得的數字最大是多少 1 leq n leq 9 兩個人同時走,四維分別表示兩個人,如果兩人的路線相同那麼只能加一次即可 includeusing name...

NOIP2010 烏龜棋 四維dp

小明過生日的時候,爸爸送給他一副烏龜棋當作禮物。烏龜棋的棋盤是一行n 個格仔,每個格仔上乙個分數 非負整數 棋盤第1 格是唯一的起點,第n 格是終點,遊戲要求玩家控制乙個烏龜棋子從起點出發走到終點。烏龜棋中m 張爬行卡片,分成4 種不同的型別 m 張卡片中不一定包含所有4 種型別的卡片,見樣例 每種...