『陣列的最大代價 貪心優化DP』
<更新提示>更新提示>
<第一次更新>第一次更新>
<正文>正文>
陣列的最大代價(51nod 1270)
Description
陣列A包含N個元素A1, A2......AN。陣列B包含N個元素B1, B2......BN。並且陣列A中的每一個元素Ai,都滿足1 <= Ai <= Bi。陣列A的代價定義如下:
\[S=\sum_{i=2}^{N}|A_i-A_{i-1}|\]
(公式表示所有兩個相鄰元素的差的絕對值之和)
給出陣列B,計算可能的最大代價S。
Input Format
第1行:1個數N,表示陣列的長度(1 <= N <= 50000)。
第2 - N+1行:每行1個數,對應陣列元素Bi(1 <= Bi <= 10000)。
Output Format
輸出最大代價S。
Sample Input
5
10
1
10
1
10
Sample Output
36
解析
化簡題目大意可以得知:即求一個數組限制下的相鄰兩項最大差值和。
有一個很簡單的暴力DP思路如下:
設\(f[i][j]\)代表前\(i\)項當中,第\(i\)個數字取\(j\)的最大和。
\(f[i][j]=max\{f[i-1][k]+|j-k|\}\)
\((i=1 - n,j=1 - B_i,k=1 - B_{i-1})\)
時間複雜度\(O(nMax\{b_i\}^2)\)
不怕暴力TLE,就怕暴力不敢想。沒錯,最簡單的暴力就是這道題的關鍵。
我們可以用貪心對這個暴力進行降維打擊
最顯然的貪心,構造\(A_i\)時極端化能得到全域性最優解。即:\(A_i\)的最優取值方案只有兩種可能,\(1\)或\(B_i\),這樣可以讓相鄰兩項的差的絕對值儘可能大。
那麼\(j\),\(k\)都只能取最大值或\(1\),直接實現\(O(1)\)轉移。可以優化一下狀態:設\(f[i][0/1]\)代表前\(i\)項當中,第\(i\)個數字取\(1\)(第二維為0)或\(B_i\)(第二維為1)的最大和。
狀態轉移方程:
\[f[i][0]=max(f[i-1][0],f[i-1][1]+|B_{i-1}-1|)\\f[i][1]=max(f[i-1][0]+|B_i-1|,f[i-1][1]+|B_i-B_{i-1}|)\]
可以滾動陣列一下把第一維的空間也優化了。
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
inline void read(int &k)
{
int w=0,x=0;char ch;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
k=(w?-x:x);return;
}
const int N=50000+80;
int n,b[N],f[2][2];
inline void input(void)
{
read(n);
for(int i=1;i<=n;i++)read(b[i]);
}
inline void dp(void)
{
f[1][0]=f[1][1]=0;
for(int i=2;i<=n;i++)
{
f[i&1][0]=max(f[i-1&1][0],f[i-1&1][1]+abs(b[i-1]-1));
f[i&1][1]=max(f[i-1&1][0]+abs(b[i]-1),f[i-1&1][1]+abs(b[i]-b[i-1]));
}
}
int main(void)
{
input();
dp();
printf("%d\n",max(f[n&1][0],f[n&1][1]));
}
考點:演算法思想的結合運用。
<後記>後記>