行のNのワインがあります。毎年あなたは左端または右端のワインのいずれかを販売しています。i番目のワインは、k番目の年に最初の価格P [i]と価格のk * pを[I]を持っています。可能な最大総利益は何ですか?
ソリューション1.ボトムアップ動的計画
状態:
DP [I] [J]:今年のワイン[I、J]の最大の可能な利益I - 0 + N - 1 - J + 1 = N + I - jは
DPの[I] [J] =最大{P [I] *(N + I - J)+ DP [I + 1] [J]、P [J] *(N + iは-j)+ DP [I]、[J - 1]}
初期化:
DP [i]は[I] = N * P [i]の
答え:
DP [0] [N - 1]
iとjをループ。この場合、ループの順序が重要です。最初 - DP [i]の[j]を計算するために、我々は、DP [I + 1] [J]とDP [i]が[1 j]を持っている必要があります。NにI + 1から昇順で1 0とjに - - これは、私たちは私がNから順にループする必要があることを意味1。
公共 INT maxProfitBottomUp(INT [] P){ int型 N = p.length。 INT [] [] DP = 新しい INT [N]、[N]。 用(int型 ; iがNを<I ++は、I = 0 {) DP [i]は[I] = N * P [i]は、 } のための(int型 I = N - 1; I> = 0; i-- ){ ため(int型、J <N; J ++ J = I + 1 ){ DP [I] [J] = Math.max(P [ I] *(N + I - J)+ DP [I + 1] [J]、P [J] *(N + iは-j)+ DP [I]、[J - 1 ])。 } } リターンDP [0] [N - 1 ]。 }
最初の間隔の長さにわたってループ、すべての可能な左スタートオーバー、ループ。
公共 INT maxProfitBottomUp(INT [] P){ int型 N = p.length。 INT [] [] DP = 新しい INT [N]、[N]。 用(int型 ; iがNを<I ++は、I = 0 {) DP [i]は[I] = N * P [i]は、 } のための(INT LEN = 2; LEN <= N; LEN ++ ){ ための(int型、L = 0; L <= N - LEN; L ++ ){ int型、R = L + LEN - 1 。 INT Y = N + L - R。 DP [L] [R]= Math.max(P [L] * Y + DP [L + 1] [R]、P [R] * Y + DP [L] [R - 1 ])。 } } 戻り DP [0] [N - 1 ]。 }
ソリューションII。動的なプログラミングをトップダウン
状態:
DP [L] [R]:最大の可能な利益我々は[L、R]をインターバルに行く前に。
DP [L] [R] = Math.max(DP [L] [R + 1] + P [R + 1] *(カレー - 1)、DP [1 - 1] [R] + P [1 - 1 ] *(カレー - 1))、カレー= N + L - R。
初期化:
DP [0] [N - 1] = 0
答え:
の最大{DP [I] [I] + P [I] * N}
公共 INT maxProfitTopDown(INT [] P){ int型 N = p.length。 INT [] [] DP = 新しい INT [N]、[N]。 DP [ 0] [N - 1] = 0 。 用(INT - ; LEN> = 1 len-- 1 LEN = N {) のための(int型 L = 0、L + LEN <= N; L ++ ){ int型 R = L + LEN - 1 。 INTカレー= N + L - R。 もし(R <N - 1 ){ DP [L] [R]= Math.max(DP [L] [R]、DP [L] [R + 1] + P [R + 1] *(カレー- 1 ))。 } 場合(L> 0 ){ DP [L] [R] = Math.max(DP [L] [R]、DP [1 - 1] [R] + P [1 - 1] *(カレー- 1 ) ); } } } int型 RES = 0 。 以下のために(int型 I 0 =; iがNを<; Iは++ ){ RES = Math.max(RES、DP [i]は[I] + P [I] * N)。 } 戻りRESと、 }
ソリューションIII。接頭和とボトムアップ動的計画
主なアイデア:私たちが想定した場合、すべての間隔は1年で始まり、すでに間隔の最大の利益を持っている[R、Lを - 1]と[L + 1、R]、その後、区間[L、R]を計算するために、我々はすべてのシフト[L、R - 1]のため年1によると[L + 1、r]は、次いで、いずれかのP [R]またはp [L]を加えます。これは、区間[L、R]のprefixsumあります。
DP [L] [R]:ワインの最大の可能な利益[L、R]年1から始まる
DP [L] [R] = Math.max(DP [L] [R - 1]、DP [L + 1] [R])+ prefixSum [L、R]
INIT:DP [i]は[I] = 1 *のP [I]
回答:DP [0] [N - 1]
公共 INT maxProfitPrefixSum(INT [] P){ int型 N = p.length。 INT [] [] DP = 新しい INT [N]、[N]。 以下のために(int型 I 0 =; iがNを<; Iは++ ){ DP [i]は[I] = P [i]は、 } INT [] prefixSum = 新しい INT [N]。 prefixSumは、[ 0]、P [= 0 ]。 用(int型、iがNを<; I 1 = I ++は){ prefixSum [I] = prefixSum [I - 1] + P [i]は、 } のために(int型 I = N - 1; I> = 0; i-- ){ ための(int型 J = I + 1、J <N; J ++ ){ DP [I] [J] = Math.max(DP [I] [J - 1]、DP [I + 1] [J])+ prefixSum [J] - (I> 0 prefixSum [I - 1]:0 )。 } } 戻り DP [0] [N - 1 ]。 }