2021-2022 ICPC, NERC, Northern Eurasia Onsite J.Job Lookup(区间dp,二维前缀和)
链接 :给出一张完整的图片,给出两点之间的价值 c i j c_{ij} cij,现在你必须建造一棵二叉树。每个点的左儿子编号小于它,右儿子编号大于他。现在两点之间的权重是 d i j ? c i j d_{ij}*c_{ij} dij?cij, d i j d_{ij} dij为了树上的两点距离,现在你要让权值最小,谁是输出每一点的父节点? n ≤ 200 n\le200 n≤2
#include<bits/stdc++.h>
using namespace std;
#define int long long
int dp[255][255], a[255][255], root[255][255], ans[255];
int dfs(int l, int r)
{
int t = root[l][r];
if (t - 1 >= l) ans[dfs(l, t - 1)] = t;
if (t + 1 <= r) ans[dfs(t + 1, r)] = t;
return t;
}
int calc(int x, int y, int xx, int yy)
{
return a[xx][yy] - a[xx][y - 1] - a[x - 1][yy] + a[x - 1][y - 1];
}
signed main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
a[i][j] = a[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1]; if(j >= i)dp[i][j] = 1e18;
}
}
for (int len = 1; len <= n; len ++) {
for (int l = 1; l + len - 1 <= n; l++) {
int r = l + len - 1;
for (int k = l; k <= r; k++) {
int d = dp[l][k - 1] + dp[k + 1][r] + calc(l, 1, k - 1, l - 1) + calc(l, k, k - 1, n) + calc(k + 1, 1, r, k) + calc(k + 1, r + 1, r, n);
if (d < dp[l][r]) {
root[l][r] = k;
dp[l][r] = d;
}
}
}
}
dfs(1, n);
for (int i = 1; i <= n; i++) {
cout << ans[i] << ' ' ;}
return 0;
}