一言(ヒトコト)

P11676 [USACO25JAN] DFS Order P

这是一道优美的题目(借用luogu题解里的话

dfs序有一个很好的性质
就是一个子树肯定是一个连续的区间

所以我们可以每个区间单独考虑

\(f[l,r]\)\(l\)一定是根,那么剩下的就是\(l\)的子树

我们考虑转移

一个新加的子树\([k+1,r]\)(这个时候我们可以类似于枚举分割点
那么也就是 \(f[l,r]=f[l,k]+f[k+1,r]+a[l,k+1]\)

我们可以把原图的一些边删掉,然后让他的加入代价改为\(-a[i,j]\)
但是这样有可能会有返祖边,不过返祖边对我们的dfs序不会有任何影响(当做没看见

那么为什么会没有横插边(别人都是这么叫的

因为当我们合并\([k+1,r]\)\([l,r]\)时,我们添加的边只可能是\((l,k+1)\) \((l,k+2)\)……

代码如下

点击查看代码
#include<bits/stdc++.h>
#define Elysia return
using namespace std;
typedef long long LL;
const int N=800;
int n;
LL a[N][N];
LL f[N][N],s[N][N];
LL sum;
int main(){
	memset(f,0x3f,sizeof(f));
	cin>>n;
	for(int j=2;j<=n;j++){
		for(int i=1;i<j;i++){
			cin>>a[i][j];
			if(a[i][j]<0){
				sum+=-a[i][j];
			}
		}
	}
	for(int i=1;i<=n;i++){
		f[i][i]=0;
	}
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			if(a[i][j]<0){
				s[i][j]=s[i][j-1]+a[i][j];
			}
			else{
				s[i][j]=s[i][j-1];
			}
		}
	}
	for(int len=2;len<=n;len++){
		for(int i=1;i+len-1<=n;i++){//左端点(根
			int j=i+len-1;、、右端点
			for(int k=i;k<j;k++){//枚举分割点(可能表述的不对
				f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[i][j]-s[i][k+1]+a[i][k+1]);
			}
		}
	}
	cout<<f[1][n]+sum;
	Elysia 0;
} 

/*
4
1
2 3
40 6 11
*/

/*
10
*/
posted @ 2026-07-30 11:03  冬冬猫  阅读(4)  评论(0)    收藏  举报