poj1849(树形dp)

树形dp,在树结构上,求最优值,求方案等dp问题,就可以考虑是树形dp


试了好几遍才a。。

方法很多,来我的

g【i】:一个人走完子树的最短dis

sum【i】:子树的总边距离乘二,就是一个人走完回到根的路程

f【i】【0】:表示两者在同一个子树中的最短距离

f【i】【1】:表示两者在不同子树中的最短距离


感觉状态的表难想,细节难处理。

这里的状态,我感觉,是根据题目的性质,分情况(因为只有可能两人在同一个子树或不同的子树两种情况),分情况来表示状态,在为了这两个状态才来维护一些其他的东西。

转移实际上推一推就出来了

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int inf=0x3f3f3f3f;

int f[100010][2],g[100010],sum[100010];

int n,s,fa[100010];

int head[100010],tot;
struct aa
{
	int to,pre,dis;
}edge[100010];
void addedge(int x,int y,int z)
{
	edge[++tot].to=y;edge[tot].dis=z;edge[tot].pre=head[x];head[x]=tot;
}



void dfs(int u)
{
	int fi=0,se=0;
	for (int i=head[u];i;i=edge[i].pre)
	{
		int v=edge[i].to;
		if (fa[u]==v) continue;
		
		sum[v]=edge[i].dis*2;
		g[v]=edge[i].dis;
		fa[v]=u;
		dfs(v);
		if (sum[v]-g[v]>fi) se=fi,fi=sum[v]-g[v];
		else if (sum[v]-g[v]>se) se=sum[v]-g[v];//注意如果只有1个孩子怎么办 
		
		sum[u]+=sum[v];
	}
	int disfa=g[u];
	
	f[u][1]=sum[u]-fi-se;//注意,两个人如果在u这个子树中,那么disfa就是走了两次,我就是在这里错了
	g[u]=sum[u]-fi-disfa;
	
	
	f[u][0]=inf;
	for (int i=head[u];i;i=edge[i].pre)
	{
		int v=edge[i].to;
		if (v==fa[u]) continue;
		
		f[u][0]=min(min(f[v][0],f[v][1])+sum[u]-sum[v],f[u][0]);
	}
	if (f[u][0]==inf) f[u][0]=sum[u];
}
int main()
{	
	scanf("%d%d",&n,&s);
	int x,y,z;
	for (int i=1;i<n;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		addedge(x,y,z);
		addedge(y,x,z);
	}
	
	
	dfs(s);
	
	printf("%d\n",min(f[s][1],f[s][0]));
	return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值