UVa 1668 Let‘s Go Green

题目大意

给定一棵有 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)  ew(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)ew(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)ew(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)ew(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值