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;
}

浙公网安备 33010602011771号