acwing 240. 食物链-java版本

题目所属分类

维护到祖宗节点距离的并查集模板:

    int p[N], d[N];
    //p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离
    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x)
        {
            int u = find(p[x]);
            d[x] += d[p[x]];
            p[x] = u;
        }
        return p[x];
    }
    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        d[i] = 0;
    }
    // 合并a和b所在的两个集合:
    p[find(a)] = find(b);
    d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量

 

原题链接

在这里插入图片描述在这里插入图片描述

代码案例:输入样例:
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
输出样例:
3

题解

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
这代表0 - 3 - 6 是同类

设d[i]:第i个节点到其父节点距离,在做路径压缩的过程中,每个结点的父节点都会变成根节点,那么距离就表示第i个节点到根节点的距离
在这里插入图片描述

事实上,d[x]始终代表到父节点的距离,只不过在find之后x的父节点直接变成了祖宗,所以逻辑上成了到祖宗的距离

在这里插入图片描述

static int find(int x) ///返回x的祖宗节点,也就是返回x的所在集合编号  + 路径压缩
    {
        if(p[x] != x) //如果x不是树根
        {
            int t = find(p[x]);//先存下根节点是谁
            d[x] += d[p[x]];
            p[x] = t;
        }
        return p[x];
    }

在这里插入图片描述

import java.util.Scanner;
public class Main{
    static int N = 50010;
    static int n, m; //n个动物,m句话
    static int[] p = new int[N];//p[]是父节点
    static int[] d = new int[N];//d[]表示到父节点的距离,在find之后,x的父节点变成祖宗节点,所以变成了到根节点的距离
  
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
         for(int i = 1; i <= n; i ++ ) p[i] = i; //初始化并查集
         int res = 0;// 记录谎话的个数
        while(m-- > 0 ){
            
            int t =scan.nextInt();
            int x = scan.nextInt();
            int y = scan.nextInt();
             if(x > n || y > n) res ++; //X或Y比N大是假话
            else
            {
                int px = find(x), py = find(y); //先找到x,y的根节点px,py
                if(t == 1) //表示说x和y是同类
                {
                    if(px == py && (d[x] - d[y]) % 3 != 0) res ++; //但寻找根节点发现不是同类,那么是谎话
                    else if(px != py)//如果还没在一个集合中,那就加到一个集合中,并更新d[],由于是第一次说xy关系,所以是真话
                    {
                        p[px] = py;//px的根节点指向py
                        d[px] = d[y] - d[x]; //因为px和py之间也有一条边,所以得更新权值
                    }
                }
                else //吃的关系
                {
                    if(px == py && (d[x] - d[y] - 1) % 3 != 0) res ++; //在一个集合里面,不满足x吃y的关系,那么为假话
                    else if(px != py)
                    {
                        p[px] = py;
                        d[px] = d[y] + 1 - d[x];
                    }
                }
            }
        }
        System.out.println(res);

 
        }
    
    static int find(int x) ///返回x的祖宗节点,也就是返回x的所在集合编号  + 路径压缩
    {
        if(p[x] != x) //如果x不是树根
        {
            int t = find(p[x]);
            d[x] += d[p[x]];
            p[x] = t;
        }
        return p[x];
    }
}

posted @   依嘫  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示