YY_More

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

这个是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;
}
posted on 2011-07-02 22:45  YY_More  阅读(276)  评论(0编辑  收藏  举报