这个是NOI2003的原题,是一道树形动态规划。题意就是找到树上的3个点a,b,c,使得ab<ac且ab+bc最大。
我们发现ab和bc总能抽象成一个T的形状,那么设最中间那个交叉点为x,那么ax,bx,cx肯定是从x连出去的3条最大的边。我们按两个方向DP,维护3个值和最大值的来源,最后枚举交叉点即可。其实这道题跟树网的核加强版差不多,多维护一个值而已。
不过我发现我写的这几道树形动规程序都很慢,不清楚是哪里做的不规范。唉~~~
这里抱怨一下:为什么有的OJ要用lld,有的要用I64d呢?为什么我的RP这么差,在每个地方都试了两次。。。(巴蜀上是I64d)
//By YY_More
#include<cstdio>
#include<cstring>
int N,M,a,b,c,h[200010];
bool got[200010];
long long f[200010][3];
struct edge{
int data;
int point;
edge *next;
};
edge *g[200010];
inline void update(int father,int son,long long value){
if (value>f[father][0]){
h[father]=son;
f[father][2]=f[father][1];
f[father][1]=f[father][0];
f[father][0]=value;
}else
if (value>f[father][1]){
f[father][2]=f[father][1];
f[father][1]=value;
} else
if (value>f[father][2]) f[father][2]=value;
};
inline void insert(int from,int to,int L){
edge *p=new edge;
(*p).data=L;
(*p).point=to;
(*p).next=g[from];
g[from]=p;
};
void dfs(int x){
got[x]=true;
edge *p=g[x];
while (p!=NULL){
if (!got[(*p).point]){
dfs((*p).point);
update(x,(*p).point,f[(*p).point][0]+(*p).data);
}
p=(*p).next;
}
};
void dp(int x){
got[x]=true;
edge *p=g[x];
while (p!=NULL){
if (!got[(*p).point]){
if ((*p).point==h[x]) update((*p).point,x,f[x][1]+(*p).data);
else update((*p).point,x,f[x][0]+(*p).data);
dp((*p).point);
}
p=(*p).next;
}
};
int main(){
scanf("%d%d",&N,&M);
for (int i=1;i<=M;i++){
scanf("%d%d%d",&a,&b,&c);
insert(a,b,c);
insert(b,a,c);
}
int root=N/2;
dfs(root);
memset(got,0,sizeof(got));
dp(root);
long long ans=0;
for (int i=1;i<=N;i++)
if (f[i][0]+2*f[i][1]+f[i][2]>ans) ans=f[i][0]+2*f[i][1]+f[i][2];
printf("%I64d\n",ans);
return 0;
}