hdu3534,恶心的树形dp,需要考虑的东西太多了

本文介绍了一种使用树形动态规划解决的问题,详细解释了如何在树结构中寻找最长路径及其实现过程。通过递归地从叶子节点向上更新每个节点的最长路径信息,最终找出整棵树中最长路径及其出现次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

是够恶心的,然而不被恶心几次,代码能力也就练不出来了

/node[x]中记录的是:
//x的子节点通过x连接(就是在x的子树内的)的最长路径为max,条数为num,
//Max1是x的子节点到x的最长距离,num1是条数
//Max2是x的子节点到x的次长距离,num2是条数

分为,如果节点都是一样的情况,

如果节点有最长和次长距离,分情况


注意这道题倒是不用计算父亲方向的最长距离,因为是统计数量,上面那个以每一个子树为基础来统计方案才能保证统计的方案是不重不漏的。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200009;
struct aa
{
	int val,to,pre;
}edge[maxn*2];
struct bb
{
	int max1,num1,max2,num2,m,n;
}node[maxn];
int n,head[maxn],tot;
void add(int x,int y,int z)
{
	edge[++tot].to=y;edge[tot].pre=head[x];head[x]=tot;edge[tot].val=z;
}
void dfs(int u,int fa)
{
	for (int i=head[u];i;i=edge[i].pre)
	if (edge[i].to!=fa) dfs(edge[i].to,u);
	
	if (edge[head[u]].pre==0&&u!=1) node[u].num1=node[u].num2=1;
	for (int v,i=head[u];i;i=edge[i].pre)
	if ((v=edge[i].to)!=fa)
	{
		if (node[v].max1+edge[i].val>node[u].max1) 
		{
			node[u].max1=node[v].max1+edge[i].val;
			node[u].num1=node[v].num1;
			node[u].n=0;
		}
		else if (node[v].max1+edge[i].val==node[u].max1) 
		node[u].n+=node[u].num1*node[v].num1,node[u].num1+=node[v].num1;
	}
	if (node[u].n==0)
	{
		for (int v,i=head[u];i;i=edge[i].pre)
		if (fa!=(v=edge[i].to))
		{
		
			if (node[v].max1+edge[i].val==node[u].max1)continue;
			if (node[v].max1+edge[i].val>node[u].max2)
			{
				node[u].max2=node[v].max1+edge[i].val;
				node[u].num2=node[v].num1;
			}
			else if (node[v].max1+edge[i].val==node[u].max2) node[u].num2+=node[v].num1;
		}
		if (node[u].max2) 
		{
			node[u].n=node[u].num1*node[u].num2;
			node[u].m=node[u].max1+node[u].max2;
		}
		else node[u].n=node[u].num1,node[u].m=node[u].max1;
	} 
	else node[u].m=node[u].max1*2;
}
int main()
{
	while (scanf("%d",&n)==1)
	{

		memset(head,0,sizeof(head));
		memset(node,0,sizeof(node));
		tot=0;
		for (int i=1;i<n;i++) 
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			add(x,y,z);add(y,x,z);
		}
		dfs(1,0);
		int ansn=0,ansm=0;
		for (int i=1;i<=n;i++)
		{
			if (node[i].m>ansm)
			{
				ansm=node[i].m;//<span style="color: rgb(0, 128, 0); line-height: 1.5; font-family: 'Courier New'; white-space: pre-wrap;">该<strong>结点为根</strong>的子树中,包含该结点的最长路径长度</span>
				ansn=node[i].n;
			}
			else if (node[i].m==ansm) ansn+=node[i].n;
		}
		printf("%d %d\n",ansm,ansn);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值