图|AcWing 846. 树的重心

2023年2月2日17:17:53
算法不难理解,实现比较麻烦,sum与res的使用很巧妙,是一个工具写法,可以背下来。
这里的e存储的是边,一个e对应着一个有向边。j = e[i],代表着i这个点到j有条边。由于是树,肯定存在i = e[j];(无相边)
由于是双向的,所以e得开2N,ne也是如此。
在树中:有n个结点,则有n-1条边,由于用图的方式表示树,也要在意每条边的方向,由于每条边两个方向,因此一共最多2*(n-1)条边,方便起见开2N条边。

树∈图,树是特殊的图,无向连通图
图有两种,一种是有向的,一种是无向的,有向图的表示方式可以用来表示无向图,因此用有向图的数据结构也可以表示树。
只要在构建图的时候,a-b和b-a这两个都添加一遍就行了,如果只添加了a-b,会漏掉b-a这种情况,这样算法跑起来有时候会有限制,就如同之前用对象表示树结构一样。

学习静态链表写法对于找工作有什么意义呢?好像没有。。emm

import java.util.*;

/**
 * @desc 使用acwing(oj)用的模板
 */
public class Main {
    
    //定义容器、常数、读入
    int N = 100010;
    Scanner jin = new Scanner(System.in);
    int[] e = new int[2*N], ne = new int[2*N], h = new int[N];
    int idx = 0;
    boolean[] st = new boolean[N];
    int n;
    int ans;
    //oj要用的main方法
    public static void main(String[] args) {new Main().run();}//在oj中调用题解方法

    void run() {

        //读入题目数据
        n = jin.nextInt();
        ans = N;
        for (int i = 0; i < n+1; i++) {
            h[i] = -1;
        }
        // Arrays.fill(h,1,n+1,-1);
        
        for (int i = 0; i < n-1; i++) {//n-1是边的数量,n是结点的数量
            int a = jin.nextInt();
            int b = jin.nextInt();
            head_insert(a,b);
            head_insert(b,a);//不能忘记
        }
        //调用解题方法
        dfs(1);
        
        //输出题解答案
        System.out.print(ans);
        
        
    }
    
    int dfs(int u){//返回值是以u为根时,其子节点的最大结点数量
        st[u] = true;
        //遍历链表
        int sum = 1; int res = 0;/*寻找最大,sum是为了求u的总和,res是为了求最大的子树数量*/
        for(int i = h[u]; i != -1; i = ne[i]){
            int j = e[i];
            if(!st[j]){
                int s = dfs(j);
                res = Math.max(res,s);
                sum += s;
            }
        }
        
        res = Math.max(res, n - sum);//外部比较
        
        ans = Math.min(ans, res);//全局比较
        return sum;
    }
    
    void head_insert(int a, int b){
        e[idx] = b;//创建新结点
        ne[idx] = h[a];//新结点指向原来的头结点,成为新的头结点
        h[a] = idx;
        idx++;
    }
    
    
    

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值