zoukankan      html  css  js  c++  java
  • [BZOJ4987]Tree

    [BZOJ4987]Tree

    题目大意

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


    很显然选的部分一定是一个联通快 ,然后考虑走这个联通快的过程

    因为走联通快有时需要回头,那么一条边可能经过1次 也可能经过两次

    这个联通快的直径是最长的一条路径,由于希望总代价最小,我们沿着直径的一端走,遇到分支就走下去再回来,一直到直径的另一头。这样使直径这条链只被走了一次,让最长的代价最小,然后总代价就最小了(好像不太会证 但这个是对的

    发现直径上的边只走一次,非直径上的边走两次。


    考虑这个东西怎么树形dp

    设dp[i][j][k]表示在i的子树中,选j个点,其中k个点为直径的两端,然后做树形背包即可
    大致的讲一下转移过程
    对于以u为根的树,枚举他的儿子v,考虑在v之前选了j个点,在v中选了t个点,就可以从
    dp[u][j]+dp[v][t]转移到dp[u][j+t]
    由于要树形背包记得倒着枚举,第三维通过0/1/2来判断u->v这条边要加几次权即可

    最终答案是

    [min_{i=1}^{n}dp[i][k][2] ]

    讲道理为啥不是dp[1][k][2]呢,求大佬评论讲解一下qwq


    #include<bits/stdc++.h>
    #define rep(i,x,y) for (int i=x;i<=y;i++) 
    #define res(i,x,y) for (int i=x;i>=y;i--)
    using namespace std;
    const int maxn=3010,inf=0x3f3f3f3f;
    struct Edge{int v,nex,dis;}edge[maxn<<1];
    int head[maxn],cnt=0,n,K;
    int dp[maxn][maxn][3],siz[maxn];
    inline int read(){
        int x=0;char ch=getchar();
        while (!isdigit(ch)) ch=getchar();
        while (isdigit(ch)) x=x*10+ch-48,ch=getchar();
        return x;
    }
    inline void addEdge(int u,int v,int dis){
        edge[++cnt]=(Edge){v,head[u],dis};head[u]=cnt;
    }
    void dfs(int u,int fa){
        dp[u][1][0]=dp[u][1][1]=dp[u][0][0]=0;siz[u]=1;
        for (int i=head[u];i;i=edge[i].nex){
            int v=edge[i].v,w=edge[i].dis;
            if (v==fa) continue;
            dfs(v,u);
            res(j,min(siz[u],K),0)
                res(k,min(siz[v],K),0){
                    dp[u][j+k][0]=min(dp[u][j+k][0],dp[u][j][0]+dp[v][k][0]+2*w);
                    dp[u][j+k][1]=min(dp[u][j+k][1],dp[u][j][1]+dp[v][k][0]+2*w);
                    dp[u][j+k][1]=min(dp[u][j+k][1],dp[u][j][0]+dp[v][k][1]+w);
                    dp[u][j+k][2]=min(dp[u][j+k][2],dp[u][j][2]+dp[v][k][0]+2*w);
                    dp[u][j+k][2]=min(dp[u][j+k][2],dp[u][j][1]+dp[v][k][1]+w);
                    dp[u][j+k][2]=min(dp[u][j+k][2],dp[u][j][0]+dp[v][k][2]+2*w);
                }
            siz[u]+=siz[v];
        }
    }
    int main(){
        n=read();K=read();
        rep(i,1,n-1){
            int u=read(),v=read(),w=read();
            addEdge(u,v,w);addEdge(v,u,w);
        }
        memset(dp,0x3f,sizeof(dp));
        dfs(1,0);
        int ans=inf;rep(i,1,n) ans=min(ans,dp[i][K][2]);
        printf("%d
    ",ans);
        getchar();getchar();
        return 0;
    }
    
  • 相关阅读:
    前端面试题目笔记-1
    前端面试题目笔记-2
    css样式重置reset
    【css】清除浮动的几种方式
    jpages中文api
    jQuery全屏滚动插件fullPage.js中文帮助文档API
    JSONP数据调用
    jsonp全国天气案例
    关于 System.IO.File.Exists 需要注意的事项
    设置、显示、移除服务启动依赖关系
  • 原文地址:https://www.cnblogs.com/ugly-CYW-lyr-ddd/p/11802078.html
Copyright © 2011-2022 走看看