Tree
Description
Data Constraint
k
<=
Solution
我们容易发现
k
=
我们发现除了起点到终点那条链上的边只走了一次外, 其他的边都经过了两次。
那么答案显然就是
2
*
我们现在就是要找树的一个点集,求出这个k个点组成的树的总边长减去最长链的最小值。
首先这
设
fi,j
表示以
i
为根的子树中选出了
设
g0i,j
表示以
i
为根的子树中选出了
设
g1i,j
表示以
i
为根的子树中选出了
转移根据定义来就可以了,详细请看标程,最后答案为
min
(
min
(
g0i,k
),
min
(
g1i,k
))。
等等,这不是
n3
的转移吗,懵了半天,看不懂题解,最后终于发现时间复杂度是
O
(
可以发现时间复杂度其实是这个东西:
每一对点只会在其 lca 处贡献一次,故为 O (
Code
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
using namespace std;
typedef long long ll;
const ll N=32e2,M=2*N,pp=9e11;
int ne[M],lb[M],la[N],size[N],fa[N];
ll co[M];
int n,m,j,k,l,i,o,oo,ppp,a,b;
ll c;
ll f[N][N],g0[N][N],g1[N][N];
void llb(int x,int y,ll z)
{ne[++oo]=la[x]; la[x]=oo; lb[oo]=y; co[oo]=z;}
ll min(ll a,ll b)
{return a<b?a:b;}
void dg(int o)
{
f[o][1]=g1[o][1]=g0[o][1]=0;
f[o][0]=0;
fo(i,2,k)f[o][i]=g0[o][i]=g1[o][i]=pp;
size[o]=1;
for(int y=la[o];y;y=ne[y])if(fa[lb[y]]==0){
int t=lb[y]; fa[t]=o; dg(t);
fd(i,min(size[o],k),1)
fd(l,min(k-i,size[t]),1)
{
f[o][i+l]=min(f[o][i+l],f[o][i]+f[t][l]+co[y]*2);
g0[o][i+l]=min(g0[o][i+l],g1[o][i]+g1[t][l]+co[y]);
g1[o][i+l]=min(g1[o][i+l],f[o][i]+g1[t][l]+co[y]);
g1[o][i+l]=min(g1[o][i+l],g1[o][i]+f[t][l]+2*co[y]);
g0[o][i+l]=min(g0[o][i+l],g0[o][i]+f[t][l]+2*co[y]);
g0[o][i+l]=min(g0[o][i+l],f[o][i]+g0[t][l]+2*co[y]);
}
fo(i,1,min(k,size[o]))g0[o][i]=min(g0[o][i],g1[o][i]);
size[o]+=size[t];
}
}
int main()
{
cin>>n>>k;
fo(i,1,n-1){
scanf("%d%d%lld",&a,&b,&c);
llb(a,b,c); llb(b,a,c);
}
fa[n]=-1; dg(n);
ll ans=pp;
fo(i,1,n)ans=min(ans,min(g0[i][k],g1[i][k]));
printf("%lld",ans);
}