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
*/

浙公网安备 33010602011771号