動態規劃:區間DP Codeforces Round #715 (Div. 2) The Sports Festival
阿新 • • 發佈:2022-04-13
Codeforces Round #715 (Div. 2) The Sports Festival
題目:
題目大意就是給你一個數組a,定義d陣列,d1等於a中一個元素時候的max-min,d2等於兩個元素時候的max-min,讓你怎麼樣選擇a陣列放入順序,使d1+d2+...dn的值最小。
很顯然,d1恆等0.因為對陣列一開始的順序不做要求,把它從小到大排序一下,保證下標小的裡面的值小。尋找狀態轉移方程,構建DP陣列,DP[I][J],I代表區間的左端點,J代表區間的右端點,DP代表這個左端點和右端點構成的區間的d之和最小,最終答案就是dp[1][n],顯然是區間DP。考慮最後一個狀態DP[i][j],此時的max 值和 min值都出現了,分倒數第二個狀態到下一個狀態,區間端點移動了,要麼是多了最小值,要麼是多了最大值,所以上一個狀態的d可能是secondmax-min or max-secondmin ,只要看這兩個哪個更小,就選擇就行了。用min函式,所以dp[i][j]=min(dp[i+1][j],dp[i][j-1])+a[j]-a[i];後面一定要加上此刻的d,一定是max-min,因為排過序,顯然就是a[j]-a[i],所以排了序十分方便.
區間DP的思路就是先算小區間再算大區間,利用區間之間的關係進行狀態轉移。
所以模型的構建就是,最外層迴圈區間長度,len從2-n,1不用考慮,因為d1恆等於0.第二層迴圈左端點,L從1->L+len-1<=n,因為右端點不能超出n,L+len-1就是右端點R的座標,然後利用狀態轉移方程求解。一定要把DP[i][i]初始化為0.只需要兩重迴圈,時間複雜度為O(n2).
上程式碼:
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 const int maxn = 2005; 5 long long dp[maxn][maxn]; 6 long long a[maxn]; 7 int main() 8 { 9 int n; 10 cin >> n; 11 for (int i = 1; i <= n; ++i)cin >> a[i]; 12 sort(a+1, a +1+ n);//既然對a陣列的順序不做要求,那麼從小到大排序一下,這樣可以保證下標小的裡面的值也小 13 for (int len = 2; len <= n; ++len)//最外層迴圈長度 len=1的時候 dp[i][i]肯定等於0 不用算 max會等於min14 { 15 for (int l = 1; l + len - 1 <= n; ++l) 16 { 17 int r = l + len - 1; 18 dp[l][r] = a[r] - a[l] + min(dp[l + 1][r], dp[l][r - 1]); 19 } 20 } 21 cout << dp[1][n]; 22 return 0; 23 }
也是順利AC了。