首页 > 试题广场 >

小美的美丽树

[编程题]小美的美丽树
  • 热度指数:1120 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

小美在观察一棵美丽的无根树。

小团问小美:“小美,我考考你,如果我选一个点为根,你能不能找出子树大小不超过K的前提下,子树内最大值和最小值差最大的子树的根是哪个点?多个点的话你给我编号最小的那个点就行了。”

小美思索一番,说这个问题难不倒他。


输入描述:

第一行两个正整数N和K,表示全树有N个节点,要求子树大小不超过K。

第二行是N个正整数空格分隔,表示每个点的点权。以点编号从1到N的顺序给出点权。

接下来N-1行每行两个正整数表示哪两个点之间有边相连。

最后一行一个正整数root表示小团所选的根节点编号为root。



输出描述:

一行,一个正整数,含义如问题描述,输出在子树大小不超过K的前提下,子树内最大值和最小值差最大的子树的根的编号

示例1

输入

5 2
1 3 2 4 5
1 2
2 3
3 4
4 5
3

输出

2

备注:

对于30%的数据点有

对于100%的数据点有

各点上的权值有,对于K有

import java.util.*;

public class Main{
    static int max=0,index=0;//最大差值,最大差值对应的最小编号
    static int[][] dp;//dp[i][0/1/2]i为根对应的最大值、最小值,节点数量
    static int k=0;
    public static void main(String[] argvs){
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        k=in.nextInt();
        int[] v=new int[n+1];
        dp=new int[n+1][3];
        
        for(int i=1;i<=n;i++) {
            v[i]=in.nextInt();
            //dp[i][1]=Integer.MAX_VALUE;
        }
        Map<Integer,Set<Integer>> g=new HashMap<>();
        for(int i=0;i<n-1;i++){
            int x=in.nextInt(),y=in.nextInt();
            Set<Integer> s1=g.computeIfAbsent(x,(a)->new HashSet<>());
            Set<Integer> s2=g.computeIfAbsent(y,(a)->new HashSet<>());
            s1.add(y);
            s2.add(x);
        }
        
        int r=in.nextInt();
        dfs(r,g,v);
        System.out.print(index);
        
        
           
    }
    
    public static void dfs(int cur,Map<Integer,Set<Integer>> g,int[] v){
        dp[cur][0]=v[cur];
        dp[cur][1]=v[cur];
        dp[cur][2]=1;
        if(!g.containsKey(cur) || g.get(cur).size()==0) return;
        Set<Integer> son=g.get(cur);
        for(int s:son){
            Set<Integer> tmp=g.get(s);
            tmp.remove(cur);
            dfs(s,g,v);
            dp[cur][0]=Math.max(dp[cur][0],dp[s][0]);
            dp[cur][1]=Math.min(dp[cur][1],dp[s][1]);
            dp[cur][2]+=dp[s][2]; 
        }
        int dis=dp[cur][0]-dp[cur][1];
        if(dp[cur][2]<=k){
            if(dis>max){
                max=dis;
                index=cur;
            }else if(max==dis){
                index=Math.min(index,cur);
            }
        } 
        
        
        
    }
}

发表于 2022-05-28 01:02:21 回复(0)
广度优先遍历,具体见代码
import java.util.*;
import java.io.*;

public class Main{
    static int poor ; //记录在递归过程中出现的符合要求最大差值
    static int index ;//最大差值的下标
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] one = br.readLine().trim().split(" ");
        int n = Integer.parseInt(one[0]);
        int k = Integer.parseInt(one[1]);
        String[] value = br.readLine().trim().split(" ");
        Node[] nodes = new Node[n]; //节点数组
        //构造节点
        for(int i = 0; i < n ; i++){
            int num = Integer.parseInt(value[i]);
            nodes[i] = new Node(num, i + 1 ,new ArrayList<Node>());
        }
        //把节点连接起来
        for(int i = 0; i < n - 1; i++){
            String[] line = br.readLine().trim().split(" ");
            int n1 = Integer.parseInt(line[0]);
            int n2 = Integer.parseInt(line[1]);
            nodes[n1 - 1].list.add(nodes[n2 - 1]);
            nodes[n2 - 1].list.add(nodes[n1 - 1]);
        }
        poor = 0;
        index = -1;
        Node node = nodes[Integer.parseInt(br.readLine()) - 1];//根节点
        //遍历根节点
        for(Node nn : node.list){
            dfs(nn, node, k);
        }
        System.out.println(index);
    }
    public static Info dfs(Node node,Node father,int k){
        int maxS = node.value;
        int minS = node.value;
        int flo = 1;//node节点中个数,flo = 1 是 node这个1
        for(Node n : node.list){//遍历连接点
            if(n != father){//父节点不遍历
                Info info = dfs(n, node, k);
                flo += info.flo;//子树中个数相加
                maxS = Math.max(maxS, info.max);
                minS = Math.min(minS, info.min);
            }
        }
        //如果节点个数小于等于k,并且最大值和最小值差比最大差大,那么替换
        if(flo <= k && poor < maxS - minS){
            poor =  maxS - minS;
            index = node.index;
        }
        //如果节点个数小于等于k,并且最大值和最小值差等于最大差而且下标更小,那么替换下标
        if( flo <= k && poor == maxS - minS && node.index < index){
            index = node.index;
        }
        return new Info(maxS, minS, flo);
    }
}
//子树返回的信息
class Info{
    int max;//子树中的最大值
    int min;//子树中的最小值
    int flo;//子树中节点个数(在确定根节点的情况下)
    public Info(int max, int min, int flo){
        this.max = max;
        this.min = min;
        this.flo = flo;
    }
}
//节点类
class Node{
    int value;//权值
    int index;//节点的下标
    List<Node> list;//连接的点
    public Node(int value,  int index, List<Node> list){
        this.value = value;
        this.index = index;
        this.list = list;
    }
}

编辑于 2022-05-26 00:32:39 回复(0)