线性的石子合并问题比较好理解,环形的转成线性的方法就是扩展数组
1 2 3 . . . n 1 2 3 ... n
依据是我们最优的取值可以是 1 --- n也能是 2 --- n + 1,所以完全可以线性来做
for(int i = 1;i <= 2 * n;i++) { if(i <= n) scanf("%d",&a[i]); else a[i] = a[i-n]; sum[i] = sum[i-1] + a[i]; }
都快忘记了线性石子合并的问题了
未涉及四边形不等式优化前
dp[i][j]表示i到j元素区间内的权值和,sum[i][j]辅助dp[i][j]的状态转移
dp[i][j] = dp[i][k] + dp[k + 1][j] + sum[i][j]
所以我们枚举起点i之前要枚举区间的长度 l
最后应用上四边形不等式
先来看看初始化问题
for(int i = 0;i <= 2*n;i++) { dp[i][i] = 0; s[i][i] = i; s[2*n][i] = 2 * n; }
dp[i][i]仅仅一个元素权值为0——————权值根据题意来计算
s[i][i] 最优分界点 k = i
s[2*n][i] = 2 * n; 防止越界,规定一个上界,最高值也就是 2* n
好的,差不多啦,四边形不等式做到现在用的也很熟练了,还是得多练啊
/* 做的快忘得也挺快啊 石子问题 dp[i][j]表示的事从i到j的最优值 如何遍历j呢,就需要遍历区间的长度啦长度为1是无效的 */ #include <iostream> #include <cstdio> #include <string.h> #include <algorithm> #define inf (1 << 30) using namespace std; const int maxn = 2 * (1e3 + 10); int dp[maxn][maxn]; int s[maxn][maxn]; int a[maxn]; int sum[maxn]; int main() { int n; while(~scanf("%d",&n)) { sum[0] = 0; for(int i = 1;i <= 2 * n;i++) { if(i <= n) scanf("%d",&a[i]); else a[i] = a[i-n]; sum[i] = sum[i-1] + a[i]; } for(int i = 0;i <= 2*n;i++) { dp[i][i] = 0; s[i][i] = i; s[2*n][i] = 2*n; } for(int l = 2;l <= n;l++)//区间长度 { for(int i = 2 * n + 1 - l;i >= 1;i--)//起点 { int j = i + l - 1;//终点 dp[i][j] = inf; for(int k = s[i][j-1];k <= s[i+1][j];k++) { int tmp = dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]; if(dp[i][j] > tmp) { dp[i][j] = tmp; s[i][j] = k; } } } } int ans = inf; for(int i = 1;i <= n;i++) { ans = min(ans,dp[i][i + n - 1]); } printf("%d ",ans); } return 0; }