1078. 旅游规划 树形dp 图论
Published on 2022-11-17 23:01 in 暂未分类 with 林动

1078. 旅游规划 树形dp 图论

    W 市的交通规划出现了重大问题,市政府下定决心在全市各大交通路口安排疏导员来疏导密集的车流。

    但由于人员不足,W 市市长决定只在最需要安排人员的路口安排人员。

    具体来说,W 市的交通网络十分简单,由 n 个交叉路口和 n−1 条街道构成,交叉路口路口编号依次为 0,1,…,n−1 。

    任意一条街道连接两个交叉路口,且任意两个交叉路口间都存在一条路径互相连接。

    经过长期调查,结果显示,如果一个交叉路口位于 W 市交通网最长路径上,那么这个路口必定拥挤不堪。

    所谓最长路径,定义为某条路径 p=(v1,v2,…,vk),路径经过的路口各不相同,且城市中不存在长度大于 k 的路径(因此最长路径可能不唯一)。

    因此 W 市市长想知道哪些路口位于城市交通网的最长路径上。

    输入格式
    第一行包含一个整数 n。

    之后 n−1 行每行两个整数 u,v,表示编号为 u 和 v 的路口间存在着一条街道。

    输出格式
    输出包括若干行,每行包括一个整数——某个位于最长路径上的路口编号。

    为了确保解唯一,请将所有最长路径上的路口编号按编号顺序由小到大依次输出。

    数据范围
    1≤n≤2×105
    输入样例:
    10
    0 1
    0 2
    0 4
    0 6
    0 7
    1 3
    2 5
    4 8
    6 9
    输出样例:
    0
    1
    2
    3
    4
    5
    6
    8
    9

    思路
    这本身是一个无根树,可以对每个节点都作为根去求,但是这样会超时
    
    任取一个节点作为根,由直径的性质可以知道,直径中必然有一点是最高点,不管这点是不是根节点,因此我们第一遍(自底向上)dfs时求出当前节点向下的两个最大路径时取一下max就可以得到直径的长度,因为总能到达那个最高点,它的两个最大路径都是向下的。
    
    由于需要求出直径上的说所有点,那么就根据:最大的两个路径长度之和等于maxd来判断节点是否在直径上,但是因为我们第一遍dfs都是向下的,除了根节点,其它节点都还要判断向上的情况,因此需要一遍自顶向下的dfs,求出每个节点的向上最大路径值,这也是dp的过程,递推关系:up[j]要么等于上一个节点的d1(j不在u的d1路径上),要么等于d2(j在u的d1路径上)。
    
    和树的重心那题的区别:
    
    树的重心:可以一遍dfs求出向下的节点,同时根据n-sum(子节点),得出向上的值
    这题: 一遍dfs只能求出向下的情况,对向上的情况只能通过再用一个dfs用递推来求
    
    代码
    import java.util.*;
    
    public class Main{
    	static int N=200005,M=N*2,n;
    	static int idx,h[]=new int [N],ne[]=new int [M],e[]=new int [M];
    	static int d1[]=new int [N],d2[]=new int [N],up[]=new int [N],p1[]=new int [N];
    	static int maxd=0;
    	static void add(int a,int b){
    		e[idx]=b;ne[idx]=h[a];h[a]=idx++;
    	}
    	static void dfs_d(int u,int f){
    		for(int i=h[u];i!=-1;i=ne[i]){
    			int j=e[i];
    			if(j!=f){
    				dfs_d(j,u);
    				int d=d1[j]+1;
    				if(d>d1[u]){
    					d2[u]=d1[u];
    					d1[u]=d;
    					p1[u]=j;
    				}else if(d>d2[u]){
    					d2[u]=d;
    				}
    			}
    		}
    		maxd=Math.max(maxd, d1[u]+d2[u]);
    	}
    	
    	static void dfs_up(int u,int f){
    		for(int i=h[u];i!=-1;i=ne[i]){
    			int j=e[i];
    			if(j!=f){
    				up[j]=up[u]+1;
    				if(p1[u]==j)up[j]=Math.max(up[j], d2[u]+1);
    				else up[j]=Math.max(up[j],d1[u]+1);
    				dfs_up(j,u);
    			}
    		}
    	}
    	
        public static void main(String []args){
            Scanner sc=new Scanner(System.in);
            n=sc.nextInt();
            Arrays.fill(h, -1);
            for(int i=0;i<n-1;++i){
            	int a=sc.nextInt();
            	int b=sc.nextInt();
            	add(a,b);add(b,a);
            }
            dfs_d(0,-1);
            dfs_up(0,-1);
            
            for(int i=0;i<n;++i){
            	int t[]={d1[i],d2[i],up[i]};
            	Arrays.sort(t,0,3);
            	if(t[1]+t[2]==maxd){
            		System.out.println(i);
            	}
            }
        }
        
        
    }
    
    
    posted @   林动  阅读(6)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 地球OL攻略 —— 某应届生求职总结
    · 周边上新:园子的第一款马克杯温暖上架
    · Open-Sora 2.0 重磅开源!
    · 提示词工程——AI应用必不可少的技术
    · .NET周刊【3月第1期 2025-03-02】
    点击右上角即可分享
    微信分享提示