@Acqua
2019-02-23T06:49:07.000000Z
字数 1519
阅读 1225
动态规划
给定个带权的点。最开始按照至标号顺序排列,可以用栈调整输出顺序。设第个点第个输出,求。
区间。表示区间中的点全部输出的最小花费。
初值:当中的点按原顺序输出,,然后再来摆放第个点的位置。注意:此处只考虑区间,与前后无关。
转移:
枚举区间长度{
枚举区间左端点{
计算区间右端点;
枚举区间断点(即原本第个输出的点后调到第个输出){
直接按照题意计算后调后的值,和比较更新,
即。
是因为无论区间中的人的顺序怎么换,所有人都需要多等待区间中的人出去,这是原本计算时没有考虑到的。
}
}
}
优化:其中连续求和可以预处理。
答案:。
数据范围估计:最坏情况答案为,不会爆。
区间思想:以短求长,以子区间值推导当前区间值。
合并答案时要注意值的定义(是否需要做调整)。
// La pluie told me to be serious.#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int N = 100 + 2;int a[N], dp[N][N], sum[N];int main(){int T, n, cnt = 0;scanf("%d", &T);while(T--){scanf("%d", &n);memset(dp, 0, sizeof(dp));for(int i = 1; i <= n; i++){scanf("%d", &a[i]);sum[i] = sum[i - 1] + a[i];}for(int l = 1; l < n; l++){for(int i = 1; i + l <= n; i++){int j = i + l;dp[i][j] = sum[j] - sum[i] + dp[i + 1][j];for(int k = i + 1; k <= j; k++){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));}}}printf("Case #%d: %d\n", ++cnt, dp[1][n]);}return 0;}