动态规划:区间DP Codeforces Round #715 (Div. 2) The Sports Festival
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会等于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了。