专栏文章

P11676 [USACO25JAN] DFS Order P

P11676题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqchtyw
此快照首次捕获于
2025/12/04 02:33
3 个月前
此快照最后确认于
2025/12/04 02:33
3 个月前
查看原文

P11676 [USACO25JAN] DFS Order P

题意:
有一个 nn 个点的无向图和一个 n×nn \times n 的矩阵 aaai,j>0a_{i,j} > 0 说明这条边当前不在,加入的代价是 ai,ja_{i,j}ai,j<0a_{i,j} < 0 说明这条边当前在,删除的代价是 ai,j-a_{i,j}
可以增删一些边,使得存在一个 dfs 序是 1,2,3,,n1,2,3,\dots,n
n750n \le 750
思路:
这个数据范围不是网络流就是 dp,经过尝试会发现网络流不太好做,考虑 dp。
如果我们当前搜到了 ii,则我们要求除了走过来的这条边,ii 不能和前面的点有任何连边。
我们考虑区间 dp:设 f(i,j)f(i,j) 表示进入 ii 的子树中,最后一个搜完的是 jj
首先,有 k=j+1nmax{0,ai,k}\sum_{k=j+1}^n \max\{0,-a_{i,k}\} 的代价,因为如果 jj 之后 ii 回溯了那么是不能和后面有边的。
我们先不考虑这个代价,我们类似树形 dpdp 考虑一个子树一个子树的加入。
枚举一个 jj,考虑能转移到哪些状态。
我们枚举下一个子树到 kk,则转移就是:
f(i,j)+f(j+1,j+k)+max{0,ai,j+1}f(i,j+k)f(i,j) + f(j+1,j+k) + \max\{0,a_{i,j+1}\} \to f(i,j+k)
这样就能 O(n2)O(n^2) 求出所有 fi(j)f_i(j),总的时间复杂度就是 O(n3)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;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...