合唱團(動態規劃問題)

2021-08-18 09:50:30 字數 3087 閱讀 6990

題目描述

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

輸入描述:

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

輸出描述:

輸出一行表示最大的乘積。

示例1

輸入 3

7 4 7

2 50

輸出 49

問題**

這樣的思路其實和遞迴一致,首先確認前n個人的選擇方案,然後再遍歷第n+1個人的可選方案,如果第n+2層,那麼確定了n+1的方案之後可以下鑽一層,如果當前的可選方案全部遍歷完畢,那麼就上鑽一層,直至無新的可選方案。

這裡需要乙個類似棧的結構來儲存當前已經選擇的方案,和下一輪的待選位置。在我的個人實踐中,我覺得用陣列+游標會更加方便一些。當然採用遍歷的方式的**時間複雜度很高,最後無法滿足題目的時間限制(在文章最後,我會附上這種思路的實現**)

基於這樣的考慮,我們可以把問題縮小為,求解前 i 個人中 k-1 個人的能力乘積最大值,(i的取值範圍為 k-1到n),然後利用這個結果,我們可以得到在前i+1個人中選擇k個人(包含第i+1個人)的能力乘積最大值,通過比較的結果,我們可以拿到全域性最大值。

我們可以將問題遞迴的縮減下去,直至將問題分解為 求解前 i 個人中 1 個人的能力最大值乘積(即能力值本身)

上面文字可能顯得有些晦澀,我接下來用符號來描述,希望對讀者理解方法本質有幫助。

首先定義陣列 dpmax[ k ] [n ] : dpmax[i][j]表示從前j個人中選擇i個人(需要包括第j個人),在這種情況下我們能得到的最大數字成績。

dpmax[ k] [ j ] = abilitylist[j] * max ( dpmax[k-1] [ h] ) h0 && j - h >d

另外我們基於題目可以得知dpmax[1][i] : dpmax[1][j] = abilitylist[j]

將上面的過程理順,我們可以通過求解 max( dpmax[k ][h] ) h屬於於[ k , n] 來獲得全域性最大值。

最後我們討論一下能力值可能存在負數的問題,在一開始的問題分析的時候,如果考慮這一部分,那麼會干擾我們的思路。如果我們需要得到在前i個人中選擇j個人(包含第i個人)的情況下,得到乘積最大值。如果第i個人是負數,那麼他就要求我們需要求得在前i-1個人中選擇j-1個人的情況下,得到乘積最小值。如果第i個人的能力值是正數,我們仍然是需要求得在前i-1個人中選擇j-1個人的情況下,得到乘積最大值。

基於這樣的分析,我們需要維護2個dp陣列,乙個用來維護上一輪最小值,乙個用來維護上一輪的最大值。

public

class dpmain

int k = in.nextint();

int d = in.nextint();

//定義dp陣列

//dp[i][j] 表示從前j個數中選擇包含第j個數的數列的計算值

long dpmaxlist = new

long[k+1][numcount+1];

long dpminlist = new

long[k+1][numcount+1];

//首先初始化dp[1]

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

long cachedmaxvalue = 0;

long cachedminvalue = 0;

for(int layer = 2; layer <= k ; layer++)

if(cachedminvalue > multiplymin)

}else

if(cachedminvalue > multiplymax)}}

dpmaxlist[layer][j] = cachedmaxvalue;

dpminlist[layer][j] = cachedminvalue;}}

long globalkmax = long.min_value;

for(int i = k ; i <= numcount ; i++)

}system.out.println(globalkmax);

}}

這個實現肯定不是最優實現,**基本展現了我之前對問題的分析。這裡給出乙個可行的優化方案,因為我們只需要維護前兩2輪的最小值和最大值,所以dp陣列可以沒必要開這麼大,當然這個也是dp問題常見的優化方法之一。

public

class main

int k = in.nextint();

int d = in.nextint();

long maxvalue = long.min_value;

int indexlist = new

int[k];

//初始化資料

int valuecache = 1;

indexlist[0] = -1;

int selectindex = 0;//指向現在正在挑選的位置

//開始遍歷

while(true)

indexlist[selectindex]++;

int cachedcurrentindexvalue = indexlist[selectindex];

if ((k - selectindex) > (numcount - cachedcurrentindexvalue))

if(selectindex > 0 && (cachedcurrentindexvalue - indexlist[selectindex-1]) > d )

if(selectindex == (k-1))

if (maxvalue < multiplyvalue)

}else

}system.out.println(maxvalue);

}}

動態規劃 合唱團

動態規劃 合唱團 時間限制 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位同學的身高,計算最少需要幾位...