• BZOJ_4987_Tree_树形DP


    BZOJ_4987_Tree_树形DP

    Description

    从前有棵树。
    找出K个点A1,A2,…,Ak。
    使得∑dis(AiAi+1),(1<=i<=K-1)最小。

    Input

    第一行两个正整数n,k,表示数的顶点数和需要选出的点个数。
    接下来n-l行每行3个非负整数x,y,z,表示从存在一条从x到y权值为z的边。
    I<=k<=n。
    l<x,y<=n
    1<=z<=10^5
    n <= 3000

    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

    考场上写了个贪心的树形背包水了50分。
    说真的这状态其实好简单的不知道为什么没想到。
    可以发现选的一定是一个连通块。
    在一个连通块内的走法肯定是沿着直径的一个端点走向另一个端点,中间经过剩余的点。
    这样代价是总边权*2-直径长度。
    设f[i][j][k]表示i的子树内选了j个点,其中子树里有k个点是直径的端点(k<=2)。
    转移的话很简单,考虑父亲到儿子连的这条边对答案贡献几次即可。
     
    代码:
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    using namespace std;
    #define N 3050
    #define _min(x,y) ((x)<(y)?(x):(y))
    int head[N],to[N<<1],nxt[N<<1],val[N<<1],n,cnt,K,f[N][N][3],a[N];
    int ans=1<<30,siz[N];
    inline void add(int u,int v,int w) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
    }
    void upd(int &x,int y) {if(x>y) x=y;}
    void dp(int x,int y) {
    	int i,j,k; siz[x]=1;
    	f[x][1][0]=f[x][1][1]=0;
    	for(i=head[x];i;i=nxt[i]) {
    		if(to[i]!=y) {
    			dp(to[i],x);
    			for(j=siz[x];j;j--) {
    				for(k=siz[to[i]];k;k--) {
    					int w=val[i],w2=w<<1;
    					upd(f[x][j+k][0],f[x][j][0]+f[to[i]][k][0]+w2);
    					upd(f[x][j+k][1],f[x][j][0]+f[to[i]][k][1]+w);
    					upd(f[x][j+k][1],f[x][j][1]+f[to[i]][k][0]+w2);
    					upd(f[x][j+k][2],f[x][j][0]+f[to[i]][k][2]+w2);
    					upd(f[x][j+k][2],f[x][j][1]+f[to[i]][k][1]+w);
    					upd(f[x][j+k][2],f[x][j][2]+f[to[i]][k][0]+w2);
    				}
    			}
    			siz[x]+=siz[to[i]];
    		}
    	}
    	ans=min(ans,f[x][K][2]);
    }
    int main() {
    	memset(f,0x3f,sizeof(f));
    	scanf("%d%d",&n,&K);
    	int i,x,y,z;
    	for(i=1;i<n;i++) {
    		scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z);
    	}
    	dp(1,0);
    	printf("%d
    ",ans);
    }
    
  • 相关阅读:
    机器学习中规则化和模型选择知识
    关于arcengine权限的设置
    arcengine 实现调用arctoolbox中的dissolove
    基于手机令牌的屏保软件设计与实现
    RelativeLayout中最底的View一个View.layout_marginBottom无效
    Citrus Engine简单Demo
    Java菜鸟学习笔记(23)--继承篇(二):继承与组合
    uva 579 ClockHands 几何初接触 求时针与分针的夹角
    OpenCV中GPU函数
    html监听,键盘事件
  • 原文地址:https://www.cnblogs.com/suika/p/9463889.html
Copyright © 2020-2023  润新知