news 2026/4/16 13:40:46

UVa 115 Climbing Trees

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UVa 115 Climbing Trees

题目分析

本题要求根据输入的父子关系对(child-parent pairs\texttt{child-parent pairs}child-parent pairs)构建一个家族树,然后对一系列查询对(query pairs\texttt{query pairs}query pairs)判断两人之间的亲属关系,并按照特定格式输出。关系包括直接父子、祖孙、兄弟姐妹、堂表亲等。

关键定义

  • pppqqqkkk-descendent\texttt{descendent}descendentkkk-ancestor\texttt{ancestor}ancestor)当且仅当存在一条长度为kkk的父子链。
  • 关系分类:
    1. child / parent\texttt{child / parent}child / parent:直接父子(k=0k=0k=0),grand child/parent\texttt{grand child/parent}grand child/parentk=1k=1k=1),great grand child/parent\texttt{great grand child/parent}great grand child/parentk≥2k \ge 2k2,前缀great\texttt{great}great重复k−1k-1k1次)。
    2. sibling\texttt{sibling}sibling:共享同一父母(即000代表000removed\texttt{removed}removed000-th cousin\texttt{th cousin}th cousin)。
    3. cousin\texttt{cousin}cousin:设pppqqq的最小公共祖先为rrrppprrrmmm-descendent\texttt{descendent}descendentqqqrrrnnn-descendent\texttt{descendent}descendent,则:
      • 他们是kkk-th cousin\texttt{th cousin}th cousin,其中k=min⁡(m,n)k = \min(m, n)k=min(m,n)
      • removed\texttt{removed}removedjjj次,其中j=∣m−n∣j = |m - n|j=mn
    4. no relation\texttt{no relation}no relation:不在同一家族树中。

输入限制

  • 最多300300300个不同名字,名字长度不超过303030
  • 最多100100100个查询对。
  • 无循环关系。

输出要求

  • 按格式输出关系,若removed\texttt{removed}removed次数为000则不输出removed 0
  • 数字后不加序数后缀(如st,nd,rd,th)。

解题思路

本题虽然名为“树”,但不需要显式建树,只需维护每个节点的父节点映射即可。由于名字是字符串,我们使用map<string, int>将名字映射为整数编号,便于处理。

步骤

  1. 读取父子关系

    • 每行读入child\texttt{child}childparent\texttt{parent}parent,直到遇到no.child no.parent
    • 为新名字分配编号,记录parent[child] = parent
  2. 处理查询
    对每个查询对(p,q)(p, q)(p,q)

    • 检查是否存在:若任一名字不在映射中,输出no relation
    • 检查是否在同一棵树:分别找到pppqqq的根祖先(不断找父节点直到DUMMY),若不同则输出no relation
    • 判断直接关系
      • pppqqq的祖先:根据深度输出parent / grand parent / great ... grand parent\texttt{parent / grand parent / great ... grand parent}parent / grand parent / great ... grand parent
      • pppqqq的后代:根据深度输出child / grand child / great ... grand child\texttt{child / grand child / great ... grand child}child / grand child / great ... grand child
      • pppqqq是兄弟姐妹(同一父母):输出sibling
    • 判断堂表亲关系
      • 先计算pppqqq到根节点的深度(mmmnnn)。
      • pppqqq提升到同一深度,然后同时向上找,直到找到同一父母。
      • 计算k=min⁡(m′,n′)k = \min(m', n')k=min(m,n)(提升后剩余深度),j=∣m−n∣j = |m - n|j=mn(深度差)。
      • 输出k cousin(若j=0j=0j=0)或k cousin removed j

注意:题目要求removed\texttt{removed}removed000时不输出removed 0,且数字后不加序数词。

代码

// Climbing Trees// UVa ID: 115// Verdict: Accepted// Submission Date: 2011-11-27// UVa Run Time: 0.008s//// 版权所有(C)2011,邱秋。metaphysis # yeah dot net//// [解题方法]// 模拟题。由于只需要保存父子关系,不一定要构建树。虽然方法是直接的,但是有点繁琐。#include<bits/stdc++.h>usingnamespacestd;#defineMAXN310#defineDUMMY(-1)intparent[MAXN];map<string,int>genealogy;boolisAncestor(string fName,string sName){intnFirst=genealogy[fName];intnSecond=genealogy[sName];intdepth=0;boolfound=false;while(parent[nSecond]!=DUMMY){if(parent[nSecond]==nFirst){found=true;break;}nSecond=parent[nSecond];depth++;}if(found){if(depth==0)cout<<"parent\n";elseif(depth==1)cout<<"grand parent\n";else{for(inti=1;i<depth;i++)cout<<"great ";cout<<"grand parent\n";}returntrue;}returnfalse;}boolisDescendent(string fName,string sName){intnFirst=genealogy[fName];intnSecond=genealogy[sName];intdepth=0;boolfound=false;while(parent[nFirst]!=DUMMY){if(parent[nFirst]==nSecond){found=true;break;}nFirst=parent[nFirst];depth++;}if(found){if(depth==0)cout<<"child\n";elseif(depth==1)cout<<"grand child\n";else{for(inti=1;i<depth;i++)cout<<"great ";cout<<"grand child\n";}returntrue;}returnfalse;}boolisInTree(string fName,string sName){if(genealogy.find(fName)==genealogy.end()||genealogy.find(sName)==genealogy.end()){cout<<"no relation\n";returnfalse;}returntrue;}boolisInSameTree(string fName,string sName){intnFirst=genealogy[fName];intnSecond=genealogy[sName];while(parent[nFirst]!=DUMMY)nFirst=parent[nFirst];while(parent[nSecond]!=DUMMY)nSecond=parent[nSecond];if(nFirst!=nSecond){cout<<"no relation\n";returnfalse;}returntrue;}boolisSibling(string fName,string sName){intnFirst=genealogy[fName];intnSecond=genealogy[sName];if(parent[nFirst]!=DUMMY&&parent[nSecond]!=DUMMY&&parent[nFirst]==parent[nSecond]){cout<<"sibling\n";returntrue;}returnfalse;}boolisCousin(string fName,string sName){intnFirst=genealogy[fName];intnSecond=genealogy[sName];intn=0,m=0;while(parent[nFirst]!=DUMMY){nFirst=parent[nFirst];n++;}while(parent[nSecond]!=DUMMY){nSecond=parent[nSecond];m++;}nFirst=genealogy[fName];nSecond=genealogy[sName];intbackN=n,backM=m;if(n>m){while(n>m){nFirst=parent[nFirst];n--;}while(parent[nFirst]!=parent[nSecond]){nFirst=parent[nFirst];nSecond=parent[nSecond];n--;}backN-=n;backM-=n;cout<<backM<<" cousin removed "<<(backN-backM)<<"\n";}elseif(m>n){while(m>n){nSecond=parent[nSecond];m--;}while(parent[nFirst]!=parent[nSecond]){nFirst=parent[nFirst];nSecond=parent[nSecond];m--;}backN-=m;backM-=m;cout<<backN<<" cousin removed "<<(backM-backN)<<"\n";}else{while(parent[nFirst]!=parent[nSecond]){nFirst=parent[nFirst];nSecond=parent[nSecond];n--;m--;}cout<<(backN-n)<<" cousin\n";}returntrue;}intmain(intargc,charconst*argv[]){intnNames=0;string allNames[MAXN];string childName,parentName;for(inti=0;i<MAXN;i++)parent[i]=DUMMY;while(cin>>childName>>parentName){if(childName=="no.child"&&parentName=="no.parent")break;if(genealogy.find(childName)==genealogy.end()){genealogy[childName]=nNames;allNames[nNames++]=childName;}if(genealogy.find(parentName)==genealogy.end()){genealogy[parentName]=nNames;allNames[nNames++]=parentName;}parent[genealogy[childName]]=genealogy[parentName];}while(cin>>childName>>parentName){if(!isInTree(childName,parentName))continue;if(!isInSameTree(childName,parentName))continue;if(isAncestor(childName,parentName))continue;if(isDescendent(childName,parentName))continue;if(isSibling(childName,parentName))continue;if(isCousin(childName,parentName))continue;}return0;}

复杂度分析

  • 每次查询需要向上遍历祖先链,最坏深度为O(N)O(N)O(N)NNN为节点数(≤300\le 300300)。
  • 总查询次数≤100\le 100100,因此总时间复杂度为O(N⋅Q)O(N \cdot Q)O(NQ),完全可行。

本题关键在于理清亲属关系的定义,并仔细实现各种情况的判断与输出格式。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:42:11

Docker容器启动后立即停止?破解Exited (0)状态之谜(附8种解决方案)

第一章&#xff1a;Docker容器运行状态概述Docker 容器在其生命周期中会经历多种运行状态&#xff0c;这些状态反映了容器当前所处的执行阶段。了解这些状态有助于快速诊断问题、优化资源调度以及实现自动化运维管理。容器的主要运行状态 created&#xff1a;容器已创建但尚未启…

作者头像 李华
网站建设 2026/4/12 15:36:32

Codeforces模拟赛AI辅助:VibeThinker提供算法策略建议

VibeThinker&#xff1a;小模型如何在算法竞赛中实现“降维打击” 在一场紧张的Codeforces模拟赛中&#xff0c;你卡在了一道Div.2 C题——树上每个节点都有颜色&#xff0c;要求统计每棵子树中不同颜色的数量。时间一分一秒流逝&#xff0c;思路迟迟无法成型。这时&#xff0c…

作者头像 李华
网站建设 2026/3/27 12:06:54

(Docker Compose版本兼容性全解析):从开发到部署的避坑手册

第一章&#xff1a;Docker Compose版本适配概述在使用 Docker Compose 管理多容器应用时&#xff0c;不同版本的 Compose 文件格式与 Docker 引擎之间存在兼容性要求。正确选择并适配 Compose 版本&#xff0c;是确保应用顺利部署和运行的关键前提。版本兼容性说明 Docker Comp…

作者头像 李华
网站建设 2026/3/26 5:38:55

零基础也能懂:全加器布尔表达式解析

从零开始搞懂全加器&#xff1a;不只是“112”的背后逻辑你有没有想过&#xff0c;计算机到底是怎么算数的&#xff1f;我们随手敲下5 3&#xff0c;屏幕立刻显示8。这看似简单的过程&#xff0c;其实背后藏着一套精密的数字电路机制——而这一切的起点&#xff0c;就是全加器…

作者头像 李华
网站建设 2026/4/14 11:05:04

Bilibili科普视频创意:用动画讲解VibeThinker技术亮点

VibeThinker-1.5B&#xff1a;小模型如何破解高难度数学与编程题&#xff1f; 在AI狂飙突进的今天&#xff0c;千亿参数大模型似乎成了“智能”的代名词。但你有没有想过——一个只有15亿参数的小模型&#xff0c;也能解出AIME&#xff08;美国数学邀请赛&#xff09;级别的难题…

作者头像 李华
网站建设 2026/4/15 23:36:17

【Git操作】关联远程仓库并推送本地内容

当GitHub远程仓库已存在&#xff08;包含README文件&#xff09;&#xff0c;本地项目尚未与远程仓库关联&#xff0c;这种场景下直接推送会出现「仓库不匹配」的冲突&#xff0c;核心解决思路是先拉取远程仓库的现有内容&#xff0c;与本地项目合并后再推送&#xff0c;具体操…

作者头像 李华