加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

bzoj4987 Tree 树上背包

发布时间:2020-12-13 21:28:49 所属栏目:PHP教程 来源:网络整理
导读:题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4987 题解 一道还不错的题咯。 很容易发现一个结论:这 (k) 个点构成的一定是一个连通块,并且走的时候应该是按照某种类似于 dfs 的遍历方式连续走的。 可以发现,最终答案应该有:从根的某个子

题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4987

题解

一道还不错的题咯。

很容易发现一个结论:这 (k) 个点构成的一定是一个连通块,并且走的时候应该是按照某种类似于 dfs 的遍历方式连续走的。

可以发现,最终答案应该有:从根的某个子树走出来,到某个子树中去的这样的情况,也有可能是从根到某个子树中去的情况;同时,过程中会用到从根到子树中走一遍再回到根的情况。这三种情况都需要考虑。

于是进行树形 dp,令 (dp[x][i][0/1/2]) 表示以 (x) 为根的子树中,选择了 (i) 个点,情况为从根到子树中走一遍再回到根/从根到某个子树中去(等同于从某个子树到根)/从根的某个子树走出来,到某个子树中去这三种情况,转移的时候,第二维直接背包合并,第三维是这样的:(0+0to 0,0+1to 1,1+0to 1,0+2to 2,1+1to 2,2+0to 2)


代码如下,时间复杂度为一般的背包合并 (O(nk))

#include<bits/stdc++.h>

#define fec(i,x,y) (int i = head[x],y = g[i].to; i; i = g[i].ne,y = g[i].to)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fi first
#define se second
#define pb push_back

template<typename A,typename B> inline char smax(A &a,const B &b) {return a < b ? a = b,1 : 0;}
template<typename A,typename B> inline char smin(A &a,const B &b) {return b < a ? a = b,1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int,int> pii;

template<typename I> inline void read(I &x) {
    int f = 0,c;
    while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    x = c & 15;
    while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    f ? x = -x : 0;
}

const int N = 3000 + 7;
const int INF = 0x3f3f3f3f;

int n,m,ans;
int dp[N][N][3],siz[N];

struct Edge { int to,ne,w; } g[N << 1]; int head[N],tot;
inline void addedge(int x,int y,int z) { g[++tot].to = y,g[tot].w = z,g[tot].ne = head[x],head[x] = tot; }
inline void adde(int x,int z) { addedge(x,y,z),addedge(y,z); }

inline void dfs(int x,int fa = 0) {
    dp[x][1][0] = dp[x][1][1] = 0;
    siz[x] = 1;
    for fec(i,y) if (y != fa) {
        dfs(y,x);
        int w = g[i].w;
        for (int i = std::min(m,siz[x]); i; --i)
            for (int j = 1; j <= std::min(m,siz[y]); ++j) {
                smin(dp[x][i + j][0],dp[x][i][0] + dp[y][j][0] + w * 2);
                smin(dp[x][i + j][1],dp[x][i][0] + dp[y][j][1] + w);
                smin(dp[x][i + j][1],dp[x][i][1] + dp[y][j][0] + w * 2);
                smin(dp[x][i + j][2],dp[x][i][0] + dp[y][j][2] + w * 2);
                smin(dp[x][i + j][2],dp[x][i][1] + dp[y][j][1] + w);
                smin(dp[x][i + j][2],dp[x][i][2] + dp[y][j][0] + w * 2);
            }
        siz[x] += siz[y];
    }
    smin(ans,dp[x][m][0]),smin(ans,dp[x][m][1]),dp[x][m][2]);
//  dbg("x = %d: ",x);
//  for (int i = 1; i <= m; ++i) dbg("%d:(%d,%d,%d) ",i,dp[x][i][0],dp[x][i][1],dp[x][i][2]);
//  dbg("n");
}

inline void work() {
    memset(dp,0x3f,sizeof(dp));
    ans = INF;
    dfs(1);
    printf("%dn",ans);
}

inline void init() {
    read(n),read(m);
    int x,z;
    for (int i = 1; i < n; ++i) read(x),read(y),read(z),adde(x,z);
}

int main() {
#ifdef hzhkk
    freopen("hkk.in",stdin);
#endif
    init();
    work();
    fclose(stdin),fclose(stdout);
    return 0;
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读