[关闭]
@Acqua 2019-02-23T06:49:07.000000Z 字数 1519 阅读 1225

HDU4283 You Are the One(Feb. 3rd, 2019) 区间DP

动态规划

题目来源

题意

给定个带权的点。最开始按照标号顺序排列,可以用栈调整输出顺序。设第个点第个输出,求

原理

区间表示区间中的点全部输出的最小花费。
初值:当中的点按原顺序输出,,然后再来摆放第个点的位置。注意:此处只考虑区间,与前后无关。
转移:
枚举区间长度
枚举区间左端点
计算区间右端点
枚举区间断点(即原本第个输出的点后调到第个输出){
直接按照题意计算后调后的值,和比较更新,

是因为无论区间中的人的顺序怎么换,所有人都需要多等待区间中的人出去,这是原本计算时没有考虑到的。



优化:其中连续求和可以预处理。
答案:
数据范围估计:最坏情况答案为,不会爆

反思

区间思想:以短求长,以子区间值推导当前区间值。
合并答案时要注意值的定义(是否需要做调整)。

代码

  1. // La pluie told me to be serious.
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<iostream>
  5. using namespace std;
  6. const int N = 100 + 2;
  7. int a[N], dp[N][N], sum[N];
  8. int main(){
  9. int T, n, cnt = 0;
  10. scanf("%d", &T);
  11. while(T--){
  12. scanf("%d", &n);
  13. memset(dp, 0, sizeof(dp));
  14. for(int i = 1; i <= n; i++){
  15. scanf("%d", &a[i]);
  16. sum[i] = sum[i - 1] + a[i];
  17. }
  18. for(int l = 1; l < n; l++){
  19. for(int i = 1; i + l <= n; i++){
  20. int j = i + l;
  21. dp[i][j] = sum[j] - sum[i] + dp[i + 1][j];
  22. for(int k = i + 1; k <= j; k++){
  23. dp[i][j] = min(dp[i][j], dp[i + 1][k] + a[i] * (k - i) + dp[k + 1][j] + (sum[j] - sum[k]) * (k - i + 1));
  24. }
  25. }
  26. }
  27. printf("Case #%d: %d\n", ++cnt, dp[1][n]);
  28. }
  29. return 0;
  30. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注