L2-020 功夫传人(树的建立和BFS)

简介: L2-020 功夫传人(树的建立和BFS)

描述:


一门武功能否传承久远并被发扬光大,是要看缘分的。一般来说,师傅传授给徒弟的武功总要打个折扣,于是越往后传,弟子们的功夫就越弱…… 直到某一支的某一代突然出现一个天分特别高的弟子(或者是吃到了灵丹、挖到了特别的秘笈),会将功夫的威力一下子放大N倍 —— 我们称这种弟子为“得道者”。


这里我们来考察某一位祖师爷门下的徒子徒孙家谱:假设家谱中的每个人只有1位师傅(除了祖师爷没有师傅);每位师傅可以带很多徒弟;并且假设辈分严格有序,即祖师爷这门武功的每个第i代传人只能在第i-1代传人中拜1个师傅。我们假设已知祖师爷的功力值为Z,每向下传承一代,就会减弱r%,除非某一代弟子得道。现给出师门谱系关系,要求你算出所有得道者的功力总值。


输入:


输入在第一行给出3个正整数,分别是:

N (<=105)——整个师门的总人数(于是每个人从0到N−1编号,祖师爷的编号为0);

Z——祖师爷的功力值(不一定是整数,但起码是正数);

r ——每传一代功夫所打的折扣百分比值(不超过100的正数)。

接下来有N行,第i行(i=0,⋯,N−1)描述编号为i的人所传的徒弟,格式为:

Ki ID1 ID2 IDKi

Ki 是徒弟的个数,后面跟的是各位徒弟的编号,数字间以空格间隔。

Ki为零表示这是一位得道者,这时后面跟的一个数字表示其武功被放大的倍数。

输出:

在一行中输出所有得道者的功力总值,只保留其整数部分。题目保证输入和正确的输出都不超过1010;


思路:树的建立和BFS,在题目中树根已经给出,就是祖师爷,借助队列实现BFS,但要注意n==1的情况


#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const ll maxx = 1e18;
const int N = 1e5+100;
const int pp = 1e4;
const double eps = 1e-8;
struct node{
  vector<int>ve;//存子节点 
  bool flag;//记录是否为得道者 
  double k;//在得道者中记录放大倍数,非得道者中记录徒弟个数 
  double sum;//记录功力值 
}a[N],p; 
int n,cnt,ks,son;//n 总人数 //cnt Ki  //ks 放大倍数 //son 子结点编号   
double z,ss,r,sums;//z 祖师爷功力值 //ss 缩小倍数 // r减弱百分比 //sums 得道者的功力总值 
queue<node>qu;//队列 
int main()
{
  cin>>n>>z>>r;
  if(n==1)
  {
    cin>>cnt>>ks;
    if(cnt==0) 
      cout<<ks*z;
    else
      cout<<"0";
    return 0;
  }//特判 n=1的情况,注意祖师爷本身为得道者的情况 
  ss=(100-r)/100;//算出缩小倍数 
  a[0].sum=z;//存入祖师爷的功力值 
  for(int i=0;i<n;i++)
  {
    cin>>cnt;
    if(cnt==0) 
    {
      cin>>ks;
      a[i].flag=1;
      a[i].k=ks;
    }//得道者做好标记,记录放大倍数(得道者都是叶节点) 
    else
    {
      for(int j=1;j<=cnt;j++)
      {
        cin>>son;
        a[i].ve.push_back(son); 
      }
      a[i].k=cnt;
    }//非得道者记录子节点并且记录子节点总数 
  }
  qu.push(a[0]);//放入根节点 
  while(!qu.empty())
  {
    p=qu.front();
    qu.pop();//取出队首元素 
    if(p.flag==1)
    {
      sums+=p.sum;
    }//得道者加上功力值 
    else
    { 
      for(int i=0;i<p.k;i++)
      {
        if(a[p.ve[i]].flag==1)
        {
          a[p.ve[i]].sum=p.sum*a[p.ve[i]].k*ss;//得道者的功力值一定是衰减后再放大的,注意不要漏掉放大倍数
        }
        else
        {
          a[p.ve[i]].sum=p.sum*ss;
        }
        qu.push(a[p.ve[i]]);
      }
    }//非得道者算出子节点的功力值放入队列,两个注意点 1.vector的下标从 0 开始 2. 先计算出子节点的功力值再压入队列,顺序反了计算无效 
  }
  cout<<(int)sums;//输出功力总值的整数部分 
  return 0; 
}

反思

1.注意得道者的功力值放大前也要衰减,注意细节

2.注意vector的下标从 0 开始,注意细节

3.注意先计算出功力值再进入队列,否则计算无效,注意细节;

4.注意特判 n==1 的情况,注意细节


目录
相关文章
|
4月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
44 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
8月前
|
存储 C语言
数据结构学习记录——图的遍历(深度优先搜索、广度优先搜索、为什么需要两种遍历、图不连通怎么办)
数据结构学习记录——图的遍历(深度优先搜索、广度优先搜索、为什么需要两种遍历、图不连通怎么办)
98 0
|
9月前
|
存储 算法 搜索推荐
深度优先遍历与广度优先遍历:理解它们的原理与差异
深度优先遍历与广度优先遍历:理解它们的原理与差异
L2-026 小字辈(树的建立+BFS)
L2-026 小字辈(树的建立+BFS)
97 0
|
9月前
|
存储 算法 Linux
速学数据结构 | 树 森林 二叉树 的概念详讲篇
速学数据结构 | 树 森林 二叉树 的概念详讲篇
114 1
|
算法 定位技术
图的遍历:探索节点的奥秘
本文包括深度优先遍历(DFS)和广度优先遍历(BFS)。
96 0
|
存储 算法 Java
Java数据结构与算法分析(十)B树图文详解(含完整代码)
迄今为止,已经介绍了《 二叉查找树 》和《 AVL树 》,我们始终假设可以把整个数据结构存储在内存中。可是,如果数据多到内存装不下,这就意味着必须把数据放在磁盘上,显然这些数据结构不再适用。 问题在于磁盘的I/O速度是远远不如内存访问速度的,然而从一棵树中查找到某个元素,必须从根节点一层层往下找,这每一次查找便是一次I/O操作。为了提高性能,就必须要减少查找的次数。 如能减少树的高度、增加每个节点中的元素数,便是种有效的解决方案。实现这种想法的一种方法是使用B树。
196 1
|
Java
Java数据结构54:图的深度优先遍历与广度优先遍历数据结构课程设计
给出一个无向图顶点和边的信息,输出这个无向图的深度优先遍历序列和广度优先遍历序列。从一个顶点出发如果有2个以上的顶点可以访问时,我们约定先访问编号大的那个顶点。示例输入对应的图如下图所示:
86 0
|
算法
【开卷数据结构 】图的遍历,广搜和深搜(基础)
【开卷数据结构 】图的遍历,广搜和深搜(基础)
131 0
|
存储 机器学习/深度学习 算法
Java数据结构与算法分析(六)树
树是一种非线性的数据结构,它包含n(n>=1)个节点,(n-1)条边的有穷集合。把它叫做“树”是因为它看起来像一个倒挂的树,也就是说它是根朝上,叶子朝下的。
122 0