星座

星空中有n颗星星,有n-1对星星间被人为地连上了线,每条连线有各自的长度。所有星星被连成了一个整体。现在,你要在星系中找到一个最大的十字形星座。即,你要找到两条星星构成的路径,使得它们恰好有一颗公共星(这颗公共星不能是某条路径的端点),且两条路径的长度和最大。
这里写图片描述

左图红线表示了一个合法的十字形星座,而右图的星座并不合法。

输入
第一行一个数n,表示星星的数量。
接下来n行,每行3个数x,y,z,表示第x颗星星和第y颗星星间有一条连线,它的长度是z。
输出
一行,包含一个整数,表示最大的路径长度和。若答案不存在,输出-1。

样例输入
10
3 8 6
9 3 5
1 9 2
4 8 6
2 3 3
10 4 8
5 9 5
7 2 3
6 9 1
样例输出
33

提示
20%的数据n<=1000
50%的数据n<=10,000
100%的数据n<=100,000,0<=z<=1000

这个题意真是xxxx。。。。其实题意是这样的:
对于点i
1.3条i的儿子向下伸展的路径,1条i向上伸展的路径(不能回到i)
2.4条i的儿子向下伸展的路径

这样就简洁多了。对于儿子,其实就是维护每个点4个最大的儿子
f[i][0],f[i][1],f[i][2],f[i][3]i14
但是还有一种向上的情况
g[i]i
到了i的父亲,又有两种决策,一个向上继续走,一个向下到最大的儿子
g[i]=max(g[fa[i]],f[fa[i]][0]
如果i恰好是那个最大的儿子,那么就换次大值

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int n,x,y,z,ans,tot;
int f[100005][5],fa[100005],g[100005],son[100005];
int head[100005],Next[200005],to[200005],len[200005];
void add(int x,int y,int z)
{
    tot++;
    Next[tot]=head[x];
    to[tot]=y;
    len[tot]=z;
    head[x]=tot;
}
bool cmp(int x,int y)
{
    return x>y;
}
void dfs(int k,int pre) //求f数组
{
    fa[k]=pre;
    f[k][0]=f[k][1]=f[k][2]=f[k][3]=0;
    for(int i=head[k];i!=-1;i=Next[i]) 
    if(to[i]!=pre) 
    {
        son[k]++;
        dfs(to[i],k);
        f[k][4]=f[to[i]][0]+len[i];
        sort(f[k],f[k]+5,cmp);
    }
}
void solve(int k,int pre) //求g数组
{
    for(int i=head[k];i!=-1;i=Next[i])
    if(to[i]!=pre) 
    {
        if(f[to[i]][0]+len[i]==f[k][0]) //判断是否为最大的儿子
        g[to[i]]=max(g[k],f[k][1])+len[i];
        else
        g[to[i]]=max(g[k],f[k][0])+len[i];
        solve(to[i],k);
    }
}
void dp(int k,int pre)
{
    if(son[k]>=4) ans=max(ans,f[k][0]+f[k][1]+f[k][2]+f[k][3]); //注意必须要判儿子个数,验证答案是否合法
    if(son[k]>=3&&pre!=0) ans=max(ans,f[k][0]+f[k][1]+f[k][2]+g[k]);
    for(int i=head[k];i!=-1;i=Next[i]) 
    if(to[i]!=pre) dp(to[i],k);
}       
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) head[i]=-1;
    for(int i=1;i<n;i++) 
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    dfs(1,0);
    solve(1,0);
    dp(1,0);
    cout<<ans;
    return 0;
}

今天考试心不在焉,状态一落千丈。不过我还是想说,这题的题意真是xxxx。。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值