动态规划:区间DP Codeforces Round #715 (Div. 2) The Sports Festival

 Codeforces Round #715 (Div. 2) The Sports Festival

题目链接:C. 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会等于min
14     {
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了。

posted @ 2022-04-13 08:55  朱朱成  阅读(63)  评论(0编辑  收藏  举报