JZOJ 数形dp练习4(树形dp入门)

来源:JZOJ

题目描述

大神 h k h h hkhh 给定一棵 n n 个点的边权树,由于他太强了,所以他想考考你。

让你求树中每个子树的最长链是多长?次长链是多长?(链可以长度为零,最长和次长链不能有相同的边)

备注,这里的链是子树中 根到节点的路径长度

解题思路

  • 题目要求我们求最长链和次长链,当然最长链就直接迭代就好了,次长链如何求?其实,当最长链更新时,原本的最长链就是当前的次长链;但当最长链没有更新的情况下,次长链有可能可以更新,所以仍然要迭代;
  • d i s [ i ] dis[i] 表示以 i i 为根的最长链
    d i s 2 [ i ] dis2[i] 表示以 i i 为根的次长链
  • 因为是树结构,所以根 x x 的最长链只可能与它的儿子有关;

代码君

#include <bits/stdc++.h>
using namespace std;
int dis[200010],dis2[200010],linkk[200010];
int t=0,n,st;
struct node
{
	int y,v,next;
}e[200010];
void insert(int x,int y,int v)
{
	e[++t].y=y; e[t].v=v;
	e[t].next=linkk[x]; linkk[x]=t;
}
void dfs(int x,int father)
{
	for (int i=linkk[x];i;i=e[i].next)  //邻接表查询
	{
		int y=e[i].y;
		if (y!=father)
		{
			dfs(y,x);
			if(dis[y]+e[i].v>dis[x])  //更新最长链
        	{
        		dis2[x]=dis[x];  //用最长链更新次长链
        		dis[x]=dis[y]+e[i].v;
        	}
        	else
        	 if(dis[y]+e[i].v<dis[x] && dis[y]+e[i].v>dis2[x])  //更新次长链
			  dis2[x]=dis[y]+e[i].v;
		}
	}
}
int main()
{
	freopen("T4.in","r",stdin);
	freopen("T4.out","w",stdout);
	int T;
	scanf("%d",&T);
	for (int k=1;k<=T;k++)
	{
		memset(dis,0,sizeof(dis));
		memset(dis2,0,sizeof(dis2));
		memset(linkk,0,sizeof(linkk));
		t=0;
		scanf("%d %d",&n,&st);
		for (int i=1;i<n;i++)
		{
			int x,y,v;
			scanf("%d %d %d",&x,&y,&v);
			insert(x,y,v);  //邻接表插入
			insert(y,x,v);
		}
		dfs(st,0);
		for (int i=1;i<=n;i++) printf("%d  ",dis[i]);  //打印
		printf("\n");
   		for (int i=1;i<=n;i++) printf("%d  ",dis2[i]);
   		printf("\n");
	}
	return 0;
}
发布了27 篇原创文章 · 获赞 33 · 访问量 1676

猜你喜欢

转载自blog.csdn.net/qq_43081996/article/details/104206571