Uva--1668(数学)
2015-05-14 21:09:44
题目:给出一棵N个点的树 (N<=1e5),每条边有其边权(<=100),问最少需要多少条路径才能使得每条边被覆盖的次数恰好等于边权。
思路:这题的思路比较神奇... 其间问了昂神(仰慕ing)O(∩_∩)O...
考虑计算每个点必须作为多少条路径的端点,然后累加一下即可!0.0
(1)对于每个点,我们计算出其相邻边权和 sum,以及相邻边权最大值 max,那么如果 max > sum - max,说明用最大的边权去覆盖完
其他边权后还有剩余,那么必定有 max - (sum - max) 条路径以该点为一个端点。
(2)还有一点需要考虑:有些点虽然不满足 max > sum - max,但其 sum 为奇数,我们知道一条路径经过某点的话会覆盖掉2点边权,
那么如果sum为奇数,则必有一条路径以该点为端点。
考虑到以上两点,把所有点对答案的贡献累加,最后的答案就是这个和的一半。
注意:另外还有 dfs 的写法... 当然可能还有更多的解法,因为这个题的广义性较强,解法应该也比较广。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 100010; int T,N; int sum[MAXN],tmax[MAXN]; int main(){ int a,b,c; scanf("%d",&T); for(int tt = 1; tt <= T; ++tt){ memset(sum,0,sizeof(sum)); memset(tmax,0,sizeof(tmax)); scanf("%d",&N); for(int i = 1; i < N; ++i){ scanf("%d%d%d",&a,&b,&c); sum[a] += c; sum[b] += c; tmax[a] = max(tmax[a],c); tmax[b] = max(tmax[b],c); } ll ans = 0; for(int i = 1; i <= N; ++i){ if(tmax[i] > sum[i] - tmax[i]){ ans += tmax[i] + tmax[i] - sum[i]; } else if(sum[i] & 1) ans++; } printf("Case #%d: %lld\n",tt,ans >> 1); } return 0; }