【题解 && dp】 dp例题 4

题目描述:

大神zcc and zyb(my granddaughter)给定⼀棵n个点的边权树,由于他(她)太强了,所以他想考考你。
求每一个以i为根节点的子树中以i为起点的最长链和次长链是多少?
注: 最长链和次长链必须是彼此没有相同边的两条独立的链。


样例

输入格式
第一行输入一个T( ( 1 < < T ) 2 20 (1<<T)≤2^{20} ),表示有T组数据
对于每组数据,输入总共n行 。 第一行有两个整数n和S,分别表示总点数和树根。
第2 ~ n行每行有3个整数x,y,z,表示x到y有一条边,边权为z( 0 < = z < = 10000 0<=z<=10000 )。

输出格式
输出总共 T 2 T*2
对于每组数据,输出两行
第一行输出n个数,第i个数表示以i号点作为根节点的子树的以i为起点的最长链,数之间用2个空格隔开
第二行输出n个数,第i个数表示以i号点作为根节点的子树的以i为起点的次长链,数之间用2个空格隔开


数据规模与约定

% 15 n < = 10 \%15 n<=10 (这是用来给你们找错误的 --by 凉心出题人)
% 25 n < = 100 \%25 n<=100
% 35 n < = 500 \%35 n<=500
% 45 n < = 1000 \%45 n<=1000
% 55 n < = 5000 \%55 n<=5000
% 65 n < = 10000 \%65 n<=10000
% 75 n < = 50000 \%75 n<=50000
% 100 n < = 100000 , ( 1 < < T ) < = 2 2 0 \%100 n<=100000, (1<<T)<=2^20
注意:对于上述所有输出,行末无空格。
时间限制:1s
空间限制:256MB


分析:

这是一道树形dp的题。
然后这道题目其实有个歧义:就是最长链和次长链是否可以重边。
在这里是不能重边的。

那么我们设:
m a x x 1 [ i ] maxx1[i] 表示以i为根的最长链是多少
m a x x 2 [ i ] maxx2[i] 表示以i为根的次长链是多少

因为树形dp都是从下往下更新的过程,所以对于一个根x,它的最长链也只与它的儿子有关。

显然,对于一个根x,它的最长链或者次长链只有通过它儿子的最长链才能更新。
并且它儿子的最长链只能更新它的最长链或者次长链(因为不能有重边,显然它的儿子之间不会有重边)。

那么我们可以推得一下公式:
y s o n ( x ) { m a x x 2 [ x ] = m a x x 1 [ x ]   , m a x x 1 [ x ] = m a x x 1 [ y ] + e [ i ] . v  (maxx1<maxx1[y]+e[i].v) m a x x 2 [ x ] = m a x x 1 [ y ] + e [ i ] . v  (maxx2[x]<maxx1[y]+e[i].v) y\in son(x) \begin{cases} maxx2[x]=maxx1[x] \ , maxx1[x]=maxx1[y]+e[i].v \text{ (maxx1<maxx1[y]+e[i].v)} \\ maxx2[x]=maxx1[y]+e[i].v \text{ (maxx2[x]<maxx1[y]+e[i].v)} \end{cases}


Code

#include<bits/stdc++.h>
using namespace std;
struct node{
    int y,v,Next;
}e[200010];
int linkk[100010];
int maxx1[100010];
int maxx2[100010]; 
int t;
int n,root;
int len=0;
void insert(int x,int y,int v){
    e[++len].Next=linkk[x];
    linkk[x]=len;
    e[len].y=y;
    e[len].v=v;
}
void dp(int x,int fa){
    for (int i=linkk[x];i;i=e[i].Next){
	    int y=e[i].y;
	    if (y==fa) continue;
	    dp(y,x);
	    if (maxx1[y]+e[i].v>maxx1[x])
	      maxx2[x]=maxx1[x],maxx1[x]=maxx1[y]+e[i].v;
	    else if (maxx1[y]+e[i].v>maxx2[x])
	      maxx2[x]=maxx1[y]+e[i].v;
	}
}
int main(){
    freopen("T4.in","r",stdin);
    freopen("T4.out","w",stdout);
    scanf("%d",&t);
    while (t--){
	    len=0;
	    scanf("%d %d",&n,&root);
	    for (int i=1;i<=n;i++) linkk[i]=0,maxx1[i]=0,maxx2[i]=0;
	    for (int i=1,x,y,z;i<n;i++)
	      scanf("%d %d %d",&x,&y,&z),insert(x,y,z),insert(y,x,z);
	    dp(root,0);
	    printf("%d",maxx1[1]);
	    for (int i=2;i<=n;i++)
	      printf("  %d",maxx1[i]);
	    printf("\n");
	    printf("%d",maxx2[1]);
	    for (int i=2;i<=n;i++)
	      printf("  %d",maxx2[i]);
	    if (t) printf("\n");
	}
	fclose(stdin);
	fclose(stdout);
}

猜你喜欢

转载自blog.csdn.net/huang_ke_hai/article/details/88846623