動態規劃題解 D002 合唱團

2021-08-22 06:18:51 字數 2353 閱讀 6646

有 n 個學生站成一排,每個學生有乙個能力值,牛牛想從這 n 個學生中按照順序選取 k 名學生,要求相鄰兩個學生的位置編號的差不超過 d,使得這 k 個學生的能力值的乘積最大,你能返回最大的乘積嗎?

每個輸入包含 1 個測試用例。每個測試資料的第一行包含乙個整數 n (1 <= n <= 50),表示學生的個數,接下來的一行,包含 n 個整數,按順序表示每個學生的能力值 ai(-50 <= ai <= 50)。接下來的一行包含兩個整數,k 和 d (1 <= k <= 10, 1 <= d <= 50)

輸出一行表示最大的乘積

輸入 3

7 4 7

2 50

輸出 49

題目的意思還是較為清晰的,即在一定的約束條件下尋找乙個子串行,使得子串行的值乘積最大。這裡的約束條件有兩個:乙個是子串行的個數是固定的為k;另乙個是子串行相鄰兩個序號之間的差值有乙個上限d。

拿到這樣乙個題目一開始不太好下手,比如我現在取序列中的乙個值出來,這個值位於子串行中的哪個部分呢?子串行中的下乙個值應該是向前搜尋還是向後搜尋呢?這些都是比較困惑人的。但是仔細一想,並回憶動態規劃問題中常見的思路:我們可以人為地確定當前搜尋到的這個編號為子串行中的最後乙個位置。這樣的話,我們可以設定乙個dpb[index][k],這個陣列的含義即表示,以編號index的學生作為數量為k的子串行的最後一項對應的子串行最大乘積;

同樣地,可以設定dps[index][k]表示對應子串行的最小乘積。

通過設計這樣的資料結構,我們其實將諸多變化量中的一些變數進行了固定,縮小了搜尋的範圍。

在設計出子狀態後,我們期望得到狀態轉移方程。在這裡,考慮到第二個約束條件,我們能夠搜尋的第k-1個子序列物件應當對應於原序列中編號為 [ index-d , index-1 ] 這樣區間內的。由於對於index編號的同學的價值可正可負,因此我們需要將它與前乙個狀態最大或者最小的乘積同時相乘進行比較,才能得出當前編號條件下的最大和最小;由此,可以得到狀態轉移方程為:

dpb[index][k] = max(dpb[i][k-1]*value[index] , dps[i][k-1]*value[index] ) 其中i的取值區間為 [ index-d , index-1 ]

dps[index][k] = min(dpb[i][k-1]*value[index],dps[i][k-1]*value[index] ) 其中i的取值區間為 [ index-d , index-1 ]

part 1 初值的確定

由上面的分析可以知道,對應於dpb[index][1] = value[index] ; dps[index][1] = value[index] ;

part 2 狀態轉移方程的編寫

第一重迴圈用來確定子串行的長度,即從2迴圈到k;

第二重迴圈用來確定哪些編號可以進行子串行的搜尋,這是因為比如我現在將編號1作為乙個個數為3的子串行的最後一項,這是顯然不合理的,因為它的長度根本不滿足條件。所以這個編號的範圍應該介於第一重迴圈的值到n

第三重迴圈用來確定能夠向前搜尋的長度,注意應該是max(index-d,1)作為初值的選擇

part 3 最終結果的選取

我們應該從dpb[k][k]開始遍歷到dpb[n][k]為止,選取其中最大的值作為結果

事項1: 在計算的過程中,由於涉及int的乘法,故有可能出現溢位的情況,應該使用long作為變數型別

事項2: 在確定max(index-d,1)這個第三重迴圈時,注意在迴圈過程中可能會出現dbp[a][b]中a

#include

#include

#include

#define maxnum 51

using namespace std ;

int n,k,d;

long

value[maxnum];

long dpb[maxnum][maxnum];

long dps[maxnum][maxnum];

long max(long a,long b)

long min(long a,long b)

scanf("%d%d",&k,&d);

return ;

}void init()

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

return ;

}void search()

dpb[j][i]=max(dpb[j][i],max(dpb[c][i-1]*value[j],dps[c][i-1]*value[j]));

dps[j][i]=min(dps[j][i],min(dps[c][i-1]*value[j],dpb[c][i-1]*value[j]));}}

}for(int i=k;i<=n;i++)

int main()

動態規劃 合唱團

動態規劃 合唱團 時間限制 1 sec 記憶體限制 64 mb 提交 31 解決 9 提交 狀態 討論版 n位同學站成一排,墨老師要請其中的 n k 位同學出列,使得剩下的k位同學排成合唱隊形。合唱隊形是指這樣的一種隊形 設k位同學從左到右依次編號為1,2,k,他們的身高分別為t1,t2,tk,則他...

合唱團 動態規劃

合唱團 問題描述 有 n 個學生站成一排,每個學生有乙個能力值,牛牛想從這 n 個學生中按照順序選取 k 名學生,要求相鄰兩個學生的位置編號的差不超過 d,使得這 k 個學生的能力值的乘積最大,你能返回最大的乘積嗎?dp i j 表示 依次選好第i個學生時 他在隊伍裡排第j名能力值乘積最大為多少 應...

動態規劃 合唱團

題目描述 n位同學站成一排,墨老師要請其中的 n k 位同學出列,使得剩下的k位同學排成合唱隊形。合唱隊形是指這樣的一種隊形 設k位同學從左到右依次編號為1,2,k,他們的身高分別為t1,t2,tk,則他們的身高滿足t1ti 1 tk 1 i k 你的任務是,已知所有n位同學的身高,計算最少需要幾位...