【清华集训2017模拟12.09】Tree

来源:互联网 发布:网站数据采集解决方案 编辑:程序博客网 时间:2024/05/17 09:38

Description
这里写图片描述

Input

这里写图片描述

Output

一行一个整数, 表示最小的距离和。

Sample Input

10 7
1 2 35129
2 3 42976
3 4 24497
2 5 83165
1 6 4748
5 7 38311
4 8 70052
3 9 3561
8 10 80238

Sample Output

184524

Data Constraint
这里写图片描述

题解

设g[i][j] 为以i为根的子树选择了j个点,它们构成的虚树的总长的最小值
f0[i][j]为i为根选了j个点,且当前的最长链的一个端点的i的2*边-链长的最小值
f1定义与f0相似,但是链不过端点(其实也可以过,但是不会比对应的f1更优,所以其实没有影响)

然后就按照链在子树内的情况讨论dp就可以了
看上去好像是n^3的,但是实际上复杂度是fa[x]=fa[y]size[x]size[y]把它拆开时候发现是n^2的

贴代码

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fo1(i,b,a) for(i=b;i>=a;i--)#define min(x,y) ((x)<(y)?(x):(y))#define ll long longusing namespace std;const int maxn=3005;int fi[maxn],ne[maxn*2],dui[maxn*2],dui1[maxn*2],qc[maxn],s[maxn];ll f0[maxn][maxn],f1[maxn][maxn],g[maxn][maxn];int i,j,k,l,m,n,x,y,z,now;ll ans,b;void add(int x,int y){    if (fi[x]==0) fi[x]=++now; else ne[qc[x]]=++now;    qc[x]=now; dui[now]=y; dui1[now]=z;}void dfs(int x,int y){    int i=fi[x];    s[x]=1; g[x][1]=f0[x][1]=f1[x][1]=0;    while (i){        if (dui[i]==y){            i=ne[i];            continue;        }        dfs(dui[i],x); z=dui[i];        fo1(j,min(m,s[x]),1){            fo1(k,min(s[dui[i]],m-j),1){                f1[x][j+k]=min(f1[x][j+k],b*g[x][j]+f1[z][k]+b*dui1[i]);                f1[x][j+k]=min(f1[x][j+k],f0[x][j]+f0[z][k]+dui1[i]);                f1[x][j+k]=min(f1[x][j+k],f1[x][j]+b*g[z][k]+b*dui1[i]);                f0[x][j+k]=min(f0[x][j+k],b*g[x][j]+f0[z][k]+dui1[i]);                f0[x][j+k]=min(f0[x][j+k],f0[x][j]+b*g[z][k]+b*dui1[i]);                g[x][j+k]=min(g[x][j+k],g[x][j]+g[z][k]+dui1[i]);            }        }        s[x]=s[x]+s[dui[i]];        i=ne[i];    }}int main(){    freopen("tree.in","r",stdin);    freopen("tree.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,n-1){        scanf("%d%d%d",&x,&y,&z);        add(x,y); add(y,x);    }    memset(g,1,sizeof(g));    memset(f0,1,sizeof(f0));    memset(f1,1,sizeof(f1)); b=2;    dfs(1,0);    ans=min(f0[1][m],f1[1][m]);    fo(i,2,n){        ans=min(ans,min(f0[i][m],f1[i][m]));    }    printf("%lld\n",ans);    return 0;   }
原创粉丝点击