[技巧]求树上最长链(原题TYVJ)[二星~]

原题目是TYVJ的,但是现在tyvj评测机莫名鬼畜,于是我就把数据弄了下来,并且附上评测工具~
题目及数据地址——————–>百度网盘
评测工具(柠檬Lemon)——–>同样是百度网盘呢
先说一下Lemon的配置吧,选择本地的g++路径之后,创建本地的一个测试文件夹,其他的就和cena差不多啦~,lemon没有cena的一些bug,比cena好用呢~
不过lemon默认逐字比较,需要手动设置一下忽略行末空格和文末回车

Line

Time Limit: 1000MS
Memory Limit: 32768KB

【问题描述】

求出树上一条链,使得这条链上各边的权值和最大。

【输入文件】

输入文件line.in的第一行是一个整数N(2<=N<=100000),表示是n个节点的树。 

之后N-1行,每行3个整数,a,b,c,表示a节点和b节点相邻,且边权值为c(绝对值小于等于1000)

【输出文件】

输出文件line.out包括一行,这一行只包含一个整数,就是最大的权值和。

【样例输入】

5
1 2 2
1 3 3
2 4 5
2 5 -1

【样例输出】

10

题解

如果你觉得这题是求树的直径,那么你就错了,因为这是带权的树,而且还是带负权!
所以这题我们要处理的是最长的树上链,并不是树上直径。
这样怎么办呢?树形DP?总之看见DP就头疼,那么我们就想办法绕过DP,不用DP来求解。
(下面思想来自黄学长博客,由于博文太多没找到原文……在此特声明一下)
开两个数组,f1,f2;f1表示当前点子树的最长链,f2表示当前节点子树的次长链,于是就有了类似DP的更新:

if(f1[u] < f1[v] + edges[i].dist)
{
    f2[u] = f1[u];
    f1[u] = f1[v] + edges[i].dist;
}
else    f2[u] = max(f2[u],f1[v]+edges[i].dist);

但是这样比树形DP要简单多了(或许这就是树形DP我并不清楚DP的广义概念%……)
这样每次取max来更新ans,最后输出ans就是正解了~
下面附上完全代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int size = 233333;
struct Edge{int to,dist;}edges[size];
int f1[size],f2[size],head[size],next[size],tot;
void build(int f,int t,int d)
{
    edges[++tot].to = t;
    edges[tot].dist = d;
    next[tot] = head[f];
    head[f] = tot;
}
int ans = 0;
void dfs(int u,int fa)
{
    for(int i = head[u];i;i = next[i])
    {
        int v = edges[i].to;
        if(v == fa) continue;
        dfs(v,u);
        if(f1[u] < f1[v] + edges[i].dist)
        {
            f2[u] = f1[u];
            f1[u] = f1[v] + edges[i].dist;
        }
        else    f2[u] = max(f2[u],f1[v]+edges[i].dist);
    }
    ans = max(ans,f1[u]+f2[u]);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1; i< n;i ++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        build(a,b,c);
        build(b,a,c);
    }
    dfs(1,0);
    printf("%d\n",ans);
    return 0;
}
/*
5
1 2 2
1 3 3
2 4 5
2 5 -1
*/

蒟蒻Orz各位大神们~




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值