P11676 [USACO25JAN] DFS Order P

· · 题解

P11676 [USACO25JAN] DFS Order P

题意:

有一个 n 个点的无向图和一个 n \times n 的矩阵 aa_{i,j} > 0 说明这条边当前不在,加入的代价是 a_{i,j}a_{i,j} < 0 说明这条边当前在,删除的代价是 -a_{i,j}

可以增删一些边,使得存在一个 dfs 序是 1,2,3,\dots,n

**思路:** 这个数据范围不是网络流就是 dp,经过尝试会发现网络流不太好做,考虑 dp。 如果我们当前搜到了 $i$,则我们要求除了走过来的这条边,$i$ 不能和前面的点有任何连边。 我们考虑区间 dp:设 $f(i,j)$ 表示进入 $i$ 的子树中,最后一个搜完的是 $j$。 首先,有 $\sum_{k=j+1}^n \max\{0,-a_{i,k}\}$ 的代价,因为如果 $j$ 之后 $i$ 回溯了那么是不能和后面有边的。 我们先不考虑这个代价,我们类似树形 $dp$ 考虑一个子树一个子树的加入。 枚举一个 $j$,考虑能转移到哪些状态。 我们枚举下一个子树到 $k$,则转移就是: $$ f(i,j) + f(j+1,j+k) + \max\{0,a_{i,j+1}\} \to f(i,j+k) $$ 这样就能 $O(n^2)$ 求出所有 $f_i(j)$,总的时间复杂度就是 $O(n^3)$。 ```cpp #include <iostream> #include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std; const int N = 755; const int inf = 0x3f3f3f3f; int n; int a[N][N] = {{0}}; int f[N][N] = {{0}}, g[N][N] = {{0}}; void cmn(int &x, int y) { x = min(x, y); } int main() { scanf("%d", &n); for (int i = 2; i <= n; i++) for (int j = 1; j < i; j++) scanf("%d", &a[j][i]); for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) g[i][j] = max(0, -a[i][j]); for (int j = n - 1; j >= i + 1; j--) g[i][j] += g[i][j + 1]; } memset(f, 0x3f, sizeof f); for (int i = n; i >= 1; i--) { f[i][i] = 0; for (int j = i; j <= n; j++) { if (f[i][j] != inf) { for (int k = 1; j + k <= n; k++) { cmn(f[i][j + k], f[i][j] + f[j + 1][j + k] + max(0, a[i][j + 1])); } } } for (int j = i; j <= n; j++) f[i][j] += g[i][j + 1]; } cout << f[1][n] << endl; return 0; } ```