HDU 6820 Tree

思路和代码借鉴的是这位博主的[https://blog.csdn.net/tianyizhicheng/article/details/107792119]
本人在他的思路上重新梳理了一下,代码同样借鉴了他的

8.4

1007 Tree

题意:给一棵n顶点的有边权的树,给出一个数字k,你需要找到一个子图G,满足下列要求:

1.G是连通图

2.在G中,最多有一个点的度超过k

3.G的总权重尽可能大

输出符合上述条件的G的总权重

题解:因为边权是非负的,贪心的策略是边能加就加。考虑树形dp,枚举哪个点是度超过k的点,dfs时访问到的当前节点u就是当前枚举的度超过k的顶点。

\(dp[i][0]\)表示i与父亲相连的情况下,以i为根的子树中得到的最大权值。其中

\(dp[i][1]\)表示i不与父亲相连,可以得到的最大权值。

先给每个点的儿子节点的\(dp[v][0]+w(u-v)\)从大到小排序,方便接下来贪心地选取。u考虑选儿子v的时候显然可以分三种情况:

1.\(v>k\),要么u和父亲相连的情况下(u最多有k-1个儿子),v替换掉u的第k-1个儿子,要么u不和父亲相连,v替换掉u的第k个儿子

2.\(v==k\),要么u和父亲相连的情况下,v替换掉u的第k-1个儿子,要么u不和父亲相连,在选了前k-1个儿子的基础上选v

3.\(v<k\),显然v肯定要选,u同样分两种情况(是否和父亲相连),直接递归

当然,u是根节点的时候,第二种情况和第三种情况是可以合并的,因为[1,k]一定是要选的,只讨论[k+1,n]替换第k个儿子的情况就可以了(即情况1)

#include<bits/stdc++.h>
using namespace std;

int q,n,k;
const int N=2e5+10;
typedef long long ll;
ll ans,dp[N][2];
struct node{
    int x;ll v;
    bool operator < (const node& a) const
    {
        return v>a.v;
    }
};
vector<node> e[N],vec[N];

void dfs(int u,int f)
{
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i].x;
        if(v==f)continue;
        dfs(v,u);
        vec[u].push_back({v,dp[v][0]+e[u][i].v});//vec里存了所有儿子的dp[v][0]+w(u-v)
    }
    sort(vec[u].begin(),vec[u].end());
    for(int i=0;i<min((int)vec[u].size(),u==1?k:k-1);i++)//如果是根节点,显然dp[u][0]可以选不超过k个儿子,否则只能选不超过k-1个儿子
        dp[u][0]+=vec[u][i].v;
    for(int i=0;i<min((int)vec[u].size(),k);i++)
        dp[u][1]+=vec[u][i].v;
}

void dfs1(int u,int f,ll s)//枚举当前的u点是度数可以超过k的那个点,s代表父亲传下来的贡献,包括u和f之间的边权
{
    for(int i=0;i<vec[u].size();i++)
    {
        int v=vec[u][i].x;
        ll w=vec[u][i].v-dp[vec[u][i].x][0];//u-v的边权
        if(u==1)
        {
            if(i>=k)
                dfs1(v,u,s+dp[u][0]-vec[u][k-1].v+w);//用v来换掉第k的儿子
            else
                dfs1(v,u,s+dp[u][0]-dp[vec[u][i].x][0]);//不需要换
        }
        else
        {
            if(i>=k)
                dfs1(v,u,max(s+dp[u][0]-vec[u][k-2].v+w,dp[u][1]-vec[u][k-1].v+w));//两者的区别在于u有没有连向父亲,所以一个是k-2,一个是k-1
            else if(i==k-1)
                dfs1(v,u,max(s+dp[u][0]-vec[u][k-2].v+w,dp[u][1]-dp[vec[u][i].x][0]));//第k可以替换掉第k-1,第二种情况是不替换
            else
                dfs1(v,u,max(s+dp[u][0]-dp[vec[u][i].x][0],dp[u][1]-dp[vec[u][i].x][0]));//不需要替换

        }
    }
    ll sum=0;
    for(int i=0;i<vec[u].size();i++)
        sum+=vec[u][i].v;
    ans=max(ans,sum+s);
}

int main()
{
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            e[i].clear();
            vec[i].clear();
            dp[i][0]=dp[i][1]=0;
        }
        for(int i=1;i<n;i++)
        {

            int u,v,d;
            scanf("%d%d%d",&u,&v,&d);
            e[u].push_back({v,d});
            e[v].push_back({u,d});
        }
        if(k==0)
        {
            printf("0\n");
            continue;
        }
        ans=0;
        if(k==1)
        {
            for(int i=1;i<=n;i++)
            {
                ll sum=0;
                for(int j=0;j<e[i].size();j++)
                    sum+=e[i][j].v;
                ans=max(ans,sum);
            }
            printf("%lld\n",ans);
            continue;
        }
        dfs(1,0);
        dfs1(1,0,0);
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2020-08-05 16:54  JWizard  阅读(187)  评论(0)    收藏  举报