《算法竞赛·快冲300题》每日一题:“树与排列”

news2025/1/17 9:09:22

算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge。
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。

文章目录

  • 题目描述
  • 题解
  • C++代码
  • Java代码
  • Python代码

树与排列” ,链接: http://oj.ecustacm.cn/problem.php?id=1834

题目描述

【题目描述】 给你一棵树和它的顶点的排列。
   可以证明:对于任何树,任何一对源点/终点,存在排列第一个节点是源点,最后一个节点是终点,排列的相邻节点之间的距离小于或等于3。
   你的任务是为该性质编写一个验证程序。
   给定这样一个排列和树,验证排列中相邻节点之间的距离是否小于或等于3。
【输入格式】 第一行为正整数T,表示存在T组测试数据,T≤50000。
   对于每组测试数据,第一行输入n,表示树的节点数量,节点编号为1-n,2≤n≤100000。
   接下来n-1行,每行两个数字a和b,表示节点a和b之间存在边。
   接下来n行,每行一个数字p,表示给定的排列。
   输入保证n总和不超过100000。
【输出格式】 对于每组测试数据,表示满足题目条件输出1,否则输出0。
【输入样例】

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

【输出样例】

1
0

题解

   本题要求检查排列中相邻两点的距离是否小于等于3,以下图的树为例。

   设给定一个排列{1 4 2 6 3 7 5 8 9},1-4距离为2,4-2距离为1,2-6距离为3,等等。
   本题显然是最近公共祖先(LCA)问题。例如求2-6之间的距离,先求得它们的公共祖先是1,那么2-6的距离等于2-1的距离加上1-6的距离。
   如果用标准的LCA算法,例如倍增法或Tarjan,对两个点x、y求一次LCA(x,y),计算复杂度为O(logn)。共T个测试,总复杂度为O(Tlogn),能通过测试。
   不过,本题的要求比较简单,只要判断两个点x、y之间的距离dis(x,y)≤3,并不用算x、y之间的距离,所以计算量很小,不需要用标准的LCA算法,用简单的LCA算法即可(《算法竞赛》清华大学出版社,罗勇军,郭卫斌著。234页,“4.8 LCA”)。
   在进行以下步骤之前,先求出所有点在树上的深度depth,例如depth[2]=2,depth[6]=3。在树上做一次DFS即可求出所有点的深度,计算复杂度为O(n)。
   下面2个步骤可以计算出di(x,y)的距离是否大于3。
   (1)从x和y中较深的点往上走,直到和另一个点等高。以(2, 6)为例,6更深,从6出发走到点3的位置停下,此时和点2等高。每往上走一步,dis(x,y)加1,例如6走到点3的位置,得dis(2,6)=1。也可以理解为x、y之间的总距离减少了1。到x、y相遇时,减少的总数就是距离dis(x, y)。在x或y往上走的过程中,如果超过了3步还没有相遇,说明dis(x, y)大于3,不符合要求,停止。
   (2)经过(1)之后,x,y等高,让x 和y 同步向上走。每走一步就判断是否相遇,如果相遇就停止。同时累加dis(x, y),如果大于3,也停止。
   以上操作的计算量很小。每次检查x、y的距离是否大于3,只需让x或y一共走3次。共T个测试,总计算量只有3T。
【重点】

C++代码

  

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
vector<int>G[N];    //邻接表,存树
int a[N];           //记录排列
int depth[N];       //depth[i]:节点i的深度
int pre[N];         //pre[i]:节点i的父节点

void dfs(int u, int fa, int d){    //计算每个点的深度,结果记录在depth[]中
    pre[u] = fa;
    depth[u] = d;
    for(auto v : G[u])
        if(v != fa)
            dfs(v, u, d + 1);
}
int main(){
    int T;    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)  G[i].clear();
        for(int i = 1; i < n; i++)  {                         //用邻接表存树
            int u, v;    scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        for(int i = 1; i <= n; i++)    scanf("%d", &a[i]);    //读排列
        dfs(1, -1, 0);                                        //DFS出所有点的深度
        int ok = 1;
        for(int i = 1; i <= n-1; i++) {
            int x = a[i], y = a[i+1], dis = 0;      //检查排列中相邻2个点
            while(dis <= 3 && depth[x] > depth[y])  //x比y深,让x往上走,直到和y深度相同
                x = pre[x], dis++;                  //x每往上走一步,dis(x,y)加1
            while(dis <= 3 && depth[y] > depth[x])  //y比x深,让y往上走,直到和x深度相同
                y = pre[y], dis++;
            while(dis <= 3 && depth[x] && x != y) 
//经过前面2个while,x、y已经走到同一层。如果它们不在同一个位置,那么就在2个子树的相同深度上
                x = pre[x], y = pre[y], dis += 2;   //x、y同时往上走,dis(x,y)加2
            if(dis > 3) {ok = 0; break;}            //不符合要求,停止
        }
        printf("%d\n",ok);
    }
    return 0;
}

Java代码

import java.util.*;

public class Main {
    static final int N = 100010;
    static int n;
    static List<Integer>[] G = new ArrayList[N];
    static int[] a = new int[N];
    static int[] depth = new int[N];
    static int[] pre = new int[N];

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int T = scanner.nextInt();
        while (T-- > 0) {
            n = scanner.nextInt();
            for (int i = 1; i <= n; i++)       G[i] = new ArrayList<Integer>();            
            for (int i = 1; i < n; i++) {
                int u = scanner.nextInt(), v = scanner.nextInt();
                G[u].add(v);
                G[v].add(u);
            }
            for (int i = 1; i <= n; i++)      a[i] = scanner.nextInt();
            
            dfs(1, -1, 0);
            int ok = 1;
            for (int i = 1; i <= n - 1; i++) {
                int x = a[i], y = a[i + 1], dis = 0;
                while (dis <= 3 && depth[x] > depth[y]) { x = pre[x];  dis++;}
                while (dis <= 3 && depth[y] > depth[x]) { y = pre[y];  dis++;}
                while (dis <= 3 && depth[x] > 0 && x != y) {
                    x = pre[x];
                    y = pre[y];
                    dis += 2;
                }
                if (dis > 3) { ok = 0;  break; }
            }
            System.out.println(ok);
        }
        scanner.close();
    }

    static void dfs(int u, int fa, int d) {
        pre[u] = fa;
        depth[u] = d;
        for (int v : G[u]) 
            if (v != fa) 
                dfs(v, u, d + 1);        
    }
}

Python代码

  

import sys
sys.setrecursionlimit(1000000)
N = 100010
G = [[] for _ in range(N)]
a = [0] * N
depth = [0] * N
pre = [0] * N
def dfs(u, fa, d):
    pre[u] = fa
    depth[u] = d
    for v in G[u]:
        if v != fa:
            dfs(v, u, d + 1)
T = int(input())
for _ in range(T):
    n = int(input())
    for i in range(1, n + 1):   G[i].clear()
    for i in range(1, n):
        u, v = map(int, input().split())
        G[u].append(v)
        G[v].append(u)
    #a[1:n + 1] = map(int, input().split())
    for i in range(1, n + 1): a[i]=int(input())
    dfs(1, -1, 0)
    ok = 1
    for i in range(1, n):
        x, y = a[i], a[i + 1]
        dis = 0
        while dis <= 3 and depth[x] > depth[y]:
            x = pre[x]
            dis += 1
        while dis <= 3 and depth[y] > depth[x]:
            y = pre[y]
            dis += 1
        while dis <= 3 and depth[x] and x != y:
            x = pre[x]
            y = pre[y]
            dis += 2
        if dis > 3:
            ok = 0
            break
    print(ok)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/896389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java云原生框架Quarkus初探

Java云原生框架Quarkus初探 Quarkus 介绍 Quarkus 是一个云原生&#xff0c;容器优先的Java应用框架&#xff0c;它号称是超音速和亚原子的框架&#xff0c;主要特点是构建速度、启动速度快和占用资源少等特点。它为OpenJDK HotSpot和GraalVM量身定制&#xff0c; 根据Java库和…

table表头颜色 element plus

原图 预期 css :deep(.el-table__header) {background-color: #F5F7FA;} :deep(.el-table tr) {background-color: rgba(0,0,0,0);} :deep(.el-table th.el-table__cell) {background-color: rgba(0,0,0,0);}

飞机打方块(一)菜单界面制作

一、创建项目 修改配置 新建anim&#xff0c;Prefabs&#xff0c;Scene&#xff0c;Script文件夹分别用于存放动画&#xff0c;预制资源&#xff0c;场景&#xff0c;脚本 新建场景和脚本&#xff0c; 1.游戏名称 新建title节点并修改属性&#xff1a; 2.开始游戏按钮 1.新建…

浙大mem项目备考上岸的三大“顽疾”

大家好&#xff01;不知道至今为止你是否已经在浙大mem项目的备考路上&#xff0c;随着今年提前批面试结束&#xff0c;相信有一部分考生已经获得了“优秀”资格&#xff0c;而有一部分考生则还没来得及申请&#xff0c;无论是哪种情况杭州达立易考教育都建议大家坚持自己的备考…

我能“C”——实用的调试技巧

什么是bug&#xff1f; 调试是什么&#xff1f;有多重要&#xff1f; debug和release的介绍。 windows环境调试介绍。 一些调试的实例。 如何写出好&#xff08;易于调试&#xff09;的代码。 编程常见的错误。 1.什么是bug&#xff1f; 世界上第一个bug是程序员赫柏发现的。 …

CSS和AJAX阶段学习记录

1、AJAX的工作原理&#xff1a; 如图所示&#xff0c;工作原理可以分为以下几步&#xff1a; 网页中发生一个事件&#xff08;页面加载、按钮点击&#xff09; 由 JavaScript 创建 XMLHttpRequest 对象 XMLHttpRequest 对象向 web 服务器发送请求 服务器处理该请求 服务器将响应…

openpnp - 板子上最小物料封装尺寸的选择

文章目录 openpnp - 板子上最小物料封装尺寸的选择概述END openpnp - 板子上最小物料封装尺寸的选择 概述 现在设备调试完了, 用散料飞达载入物料试了一下. 0402以上贴的贴别准, 贴片流程也稳, 基本不需要手工干预. 0201可以贴, 但是由于底部相机元件视觉识别成功率不是很高…

“Spring管理JavaBean的过程及Bean的生命周期“

目录 引言1.弹簧容器2. Bean的生命周期2.1 配置javaBean2.2. 解析Bean的定义2.3 检查是否需要添加自己的功能2.4 初始化2.5 实现Aware接口2.6 扩展2.7. 销毁 3. 单例模式和原型模式3.1. 单例模式3.2. 原型模式 4. 总结 引言 Spring框架是一个非常流行的Java应用程序框架&#…

Java之抽象类

Java之抽象类 抽象类概念抽象类如何使用抽象类的特性 作者简介&#xff1a; zoro-1&#xff0c;目前大一&#xff0c;正在学习Java&#xff0c;数据结构等 作者主页&#xff1a;zoro-1的主页 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f49…

Redis持久化:RDB和AOF机制详解

目录 1.Redis持久化简介 2.RDB持久化 2.1 什么是 RDB 持久化&#xff1f; 2.2 触发方式 2.3 Redis.conf中配置RDB 2.4 RDB 更深入理解 2.5 RDB优缺点 3.AOF持久化 3.1 什么是 AOF 持久化&#xff1f; 3.2 如何实现AOF 3.3 Redis.conf中配置AOF 3.4 深入理解AOF重写 4.RDB和…

Linux命令200例:zip和unzip用于压缩和解压文件(常用)

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

案例: 用户消费数据分析--Pandas

1. 数据读入 2. 数据处理–日期处理 3. 用户整体消费趋势分析 4. 用户个体消费分析 4.1 用户消费数量与消费金额关系的散点图 4.2 每位用户消费金额分布 4.2.1 消费金额贡献度折线图 用户贡献度折线图 4.2.2 消费金额占比前80%的客户&#xff0c;消费分布直方图 4.3 消费时…

【管理运筹学】第 5 章 | 整数规划 (2,割平面法及 0-1 变量的特性)

文章目录 引言三、割平面法四、0-1 型整数规划4.1 0-1 变量的特性4.1.1 投资问题4.1.2 约束条件满足个数问题 写在最后 引言 前文我们介绍了整数规划的一种求解方法——分支定界法&#xff0c;可以求解纯整数和混合整数规划问题。现在我们来学习另一种整数规划求解方法——割平…

【Java 动态数据统计图】动态数据统计思路案例(动态,排序,containsKey)五(117)

需求&#xff1a;前端根据后端的返回数据&#xff1a;画统计图&#xff1b; 1.动态获取地域数据以及数据中的平均值&#xff0c;按照平均值降序排序&#xff1b; 说明&#xff1a; X轴是动态的&#xff0c;有对应区域数据则展示&#xff1b; X轴 区域数据降序排序&#xff1b;…

CloudQuery:更好地管理你的 OceanBase 数据库

前言&#xff1a;作为 OceanBase 的生态合作伙伴&#xff0c;CloudQuery&#xff08;简称“CQ”&#xff09; 最新发布的社区版 2.2.0 新增了 OceanBase 数据库&#xff0c;为企业使用 OceanBase 数据库提供全面的支持。包括连接与认证、查询与分析、数据安全与权限管理&#x…

同伦问题与同伦算法

同伦问题 据我所知&#xff0c;这篇博客是CSDN上少数几篇讲同伦算法的博客之一考虑同伦算法的目的 扩大初值选取范围解决非线性代数方程组的全部解计算问题 同伦算法中的基本概念 考虑求的解人为地引入参数t,构造一个函数族使得 同时假设的解已知&#xff0c;从出发可以求解对…

Matplotlib数据可视化(三)

目录 1.绘图的填充 1.1 曲线下方区域的填充 1.2 填充部分区域 1.3 两条曲线之间的区域填充 1.4 直接使用fill进行填充 1.绘图的填充 绘图的填充可以调用fill_between()或fill()进行填充。 1.1 曲线下方区域的填充 x np.linspace(0,1,500) y np.sin(3*np.pi*x)*np.exp…

Python功能制作之3D方块

介绍 用python写一个黑窗口&#xff0c;窗口里面有一个白色的3D方块&#xff0c;左键按下后移动可以旋转以各个视角来看方块。 当然有需要的话&#xff0c;可以自己在代码中去更改颜色&#xff0c;直接通过RBG的参数进行更改即可。 做了两个函数&#xff1a;init[初始化]和d…

坦克大战-kotlin

坦克大战 游戏需求&#x1f447;核心玩法&#x1f447;&#x1f447;界面原型&#x1f447;&#x1f447;成品演示&#x1f447; 游戏开发1.代码实现 源码下载 专栏简介 &#x1f492;个人主页 &#x1f4f0;专栏目录 点击上方查看更多内容 &#x1f4d6;心灵鸡汤&#x1…

<CodeGeeX>基于大模型的全能AI编程助手

CodeGeex官网 智谱AI官网 CodeGeex是由清华大学 KEG 实验室和智谱 AI 公司于2023共同训练的代码生成模型 CodeGeeX 开发的AI助手。它基于深度学习技术&#xff0c;能够针对用户的问题和要求提供适当的答复和支持。CodeGeex的功能包括代码生成、自动添加注释、代码翻译以及智能问…