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

 

posted @ 2015-05-14 21:29  Naturain  阅读(233)  评论(0编辑  收藏  举报