题目大意
给定一棵有 n n n 个节点的树,每条边有边权 w ( u , v ) w_{(u,v)} w(u,v),用最小的路径覆盖所有的边,使得每条边被覆盖的次数等于其边权。
题解
考虑最坏情况,即所有边都用独立的一条路径覆盖它,则答案不会超过 ∑ ( u , v ) ∈ e w ( u , v ) \sum\limits_{(u,v)\ \in\ e} w_{(u,v)} (u,v) ∈ e∑w(u,v)考虑每个节点,设当前节点为 u u u,则理论上可以合并 ⌊ ∑ ( u , v ) ∈ e w ( u , v ) 2 ⌋ \left\lfloor\frac{\sum\limits_{(u,v)\in e}w_{(u,v)}}{2}\right\rfloor ⎣ ⎢2(u,v)∈e∑w(u,v)⎦ ⎥条边,即每两点权值两两合并。
可有些时候并不能合并这么多条边,因为如果存在
(
u
,
a
)
∈
e
(u,a)\in e
(u,a)∈e,且
w
(
u
,
a
)
>
∑
(
u
,
v
)
∈
e
w
(
u
,
v
)
2
w_{(u,a)}>\frac{\sum\limits_{(u,v)\in e}w_{(u,v)}}{2}
w(u,a)>2(u,v)∈e∑w(u,v) 时,只能合并最多
[
∑
(
u
,
v
)
∈
e
w
(
u
,
v
)
]
−
w
(
u
,
a
)
\left[\sum\limits_{(u,v)\in e}w_{(u,v)}\right]-w_{(u,a)}
⎣
⎡(u,v)∈e∑w(u,v)⎦
⎤−w(u,a) 条边。
因为路径不能重复经过某条边,因此不能让同一条边的两份权值合并。
实现上只需要判断
u
u
u 连出的最大那条边是否满足就可以了。
代码
#include<bits/stdc++.h>
using namespace std;
int T,n;
int deg[100010],maxd[100010];
int main(void)
{
scanf("%d",&T);
for(int k=1;k<=T;k++){
memset(maxd,0,sizeof maxd);
memset(deg,0,sizeof deg);
int ans=0;
scanf("%d",&n);
for(int i=1,u,v,w;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
deg[u]+=w;
deg[v]+=w;
//只需要求出每条边最大的边权是否超过总权值的一般即可。
maxd[u]=max(maxd[u],w);
maxd[v]=max(maxd[v],w);
ans+=w;
}
for(int i=1;i<=n;i++)
if((maxd[i]<<1) <= deg[i])//理论上限
ans-=deg[i]>>1;//两两合并,故减去
else //不能合并的部分
ans-=deg[i]-maxd[i];
printf("Case #%d: %d\n",k,ans);
}
return 0;
}