bzoj1261
区间dp
这道题就是把区间dp套了一件树的外衣,看见这种构造二叉搜索树的题,就可以用区间dp解决,如果优化的话似乎可以用决策单调性?
dp[l][r]表示l->r这些节点构建一颗二叉搜索树的最小频率,那么我们用记忆化搜索转移,dp[l][r]=dp[l][i-1]+dp[i+1][r]+k*(sum[r]-sum[l-1])+a[i]*c) i=l->r
这里枚举的i是指以i为根的树,那么dp式里的各个变量也很好理解,注意当l>r时dp[l][r]=0
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N = 35; const double inf = 1e100; int n; double k, c; double dp[N][N], a[N], sum[N]; double dfs(int l, int r) { if(l > r) return dp[l][r] = 0.0; if(dp[l][r] != inf) return dp[l][r]; for(int i = l; i <= r; ++i) dp[l][r] = min(dp[l][r], dfs(l, i - 1) + dfs(i + 1, r) + k * (sum[r] - sum[l - 1]) + c * a[i]); return dp[l][r]; } int main() { cin >> n >> k >> c; double S = 0; for(int i = 1; i <= n; ++i) scanf("%lf", &a[i]), S += a[i]; for(int i = 1; i <= n; ++i) a[i] /= S, sum[i] = sum[i - 1] + a[i]; for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) dp[i][j] = inf; printf("%.3f\n", dfs(1, n)); return 0; }