这个是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; }