PAT1090多叉树

1090 Highest Price in Supply Chain (25分)

A supply chain is a network of retailers(零售商), distributors(经销商), and suppliers(供应商)-- everyone involved in moving a product from supplier to customer.

Starting from one root supplier, everyone on the chain buys products from one’s supplier in a price P and sell or distribute them in a price that is r% higher than P. It is assumed that each member in the supply chain has exactly one supplier except the root supplier, and there is no supply cycle.

Now given a supply chain, you are supposed to tell the highest price we can expect from some retailers.

Input Specification:

Each input file contains one test case. For each case, The first line contains three positive numbers: N (≤105), the total number of the members in the supply chain (and hence they are numbered from 0 to N−1); P, the price given by the root supplier; and r, the percentage rate of price increment for each distributor or retailer. Then the next line contains N numbers, each number S**i is the index of the supplier for the i-th member. Sroot for the root supplier is defined to be −1. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in one line the highest price we can expect from some retailers, accurate up to 2 decimal places, and the number of retailers that sell at the highest price. There must be one space between the two numbers. It is guaranteed that the price will not exceed 1010.

Sample Input:

9 1.80 1.00
1 5 4 4 -1 4 5 3 6  

Sample Output:

1.85 2

题目大意:

我默认您已经读过题,这道题和1079这个问题几乎是同一个问题,不同之处在两处,本题对所有的零售商来说,经过供货商的层层加价,只需要计算零售商最高的价格,和最高价格的零售商的个数。 (1079每个零售商手中还有货物,本题相当于权重不用考虑了。)另一个不同之处在于,输入的格式不同了,第二行输入,每一个数据代表的是供应上的编号,而下标代表的下层孩子节点的编号。这点需要注意。当输入为-1 时,说明下标 i 就是根节点。

思路分析:

翻译成数据结构问题,就是给定一棵多叉树,让我们求解数的最后一层的深度 和最后一层的节点个数。 把这个数据求出来,我们的题目基本就完成了。

在这里插入图片描述

首先依然是我们的存储方式: 使用对象数组完成。nodes[ i ] 存储节点 i 对象Node 只需要一个成员变量 就是存放孩子的List . 后期我们通过List的size 是否为0 来判断这个节点是不是叶子节点。这一点在深度优先遍历中会用到。

其次是求解最大深度,我使用两种方式 求解,一种是深度优先遍历,一种是广度优先遍历。

对于深度优先遍历来说,我们的方法参数为DFS(root, depth) 同时用num 标记最大深度的节点个数。我们每一访问到一个叶子节点,就需要判断当前这节点的深度是否大于之前存储过的最大深度maxDepth。(最大深度初始化为-1) ,如果大于最大深度,那么说明我们找到了一个更深的深度,此时更新最大深度,同时num =1 这是因为,我们刚刚找到了一个新的最大深度节点。如果等于之前的最大深度,那么只需要num ++ ,因为现在的最大深度没有变。 如果小于最大深度,我们什么都不做,直接返回,因为这个节点不是我们要找的节点。

对于广度优先遍历来说,稍微有些不同。 我们知道一个事实,如果当前层的所有节点都刚好出队,那么下一层的所有节点都会刚好入队,也就是说,如果第 i 层的节点都刚好出队完成,那么,队列中有且仅有 第 i+1层的节点。基于此,我们每次都可以先记录下,当前队列中元素的个数 size 然后在内层循环中把这size 个节点出队,同时把它们的孩子节点入队。我们每做一次循环depth 都要加一 ,因为我们又向下进了一层。同时,最后一次size 记下的节点个数就是 最后一层的节点个数,也就是我么要求的最大深度的节点个数。

非常不幸的是由于时间限制,两种方法都没有通过全部样例。无论是 BFS 还是DFS 都只得了15分 ,希望如果您使用C/C++ 那么使用此方法应该可以轻松通过,如果您使用Java ,并且有更快的方法,希望能在留言区和大家分享。

完整代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

//9 1.80 1.00
//1 5 4 4 -1 4 5 3 6
public class Main  {
    static class Node {
        List<Integer> children = new ArrayList<>();
    }

    static int nodeNum; // 总节点个数 
    static double price; // 货物单价
    static double r;    // 加价幅度,%r 注意计算时 除以100 这是百分数
    static int maxDepth = -1;  // 最大深度 初始化为-1
    static int num = 0;
    static Node[] nodes;

    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String[] info = bf.readLine().trim().split(" ");
        nodeNum = Integer.parseInt(info[0]);
        price = Double.parseDouble(info[1]);
        r = Double.parseDouble(info[2]) / 100;
        int root = -1;
        nodes = new Node[nodeNum];
        for (int i = 0; i < nodeNum; i++)
            nodes[i] = new Node();

        String[] data = bf.readLine().split(" ");
        for (int i = 0; i < nodeNum; i++) {
            int supply = Integer.parseInt(data[i]);
            if (supply == -1)
                root = i;
            else
                nodes[supply].children.add(i); // 把孩子节点添加进去

        }
      //  DFS(root, 0);
        BFS(root);
        System.out.printf("%.2f %d", Math.pow((1 + r), maxDepth) * price, num);

    }

    // 最大深度的叶子节点有多少个,方案是:到达叶子节点时,判断当前深度是否大于最大深度,如果大于
    // num=1(最大深度节点个数)更新最大深度,如果小于,直接返回,如果等于,num++
    static void DFS(int root, int depth) {
        if (nodes[root].children.size() == 0) {
            if (depth > maxDepth) {
                maxDepth = depth;
                num = 1;
            } else if (depth == maxDepth) {
                num++;
            }
            return;
        }
        int childrenNum = nodes[root].children.size();
        for (int i = 0; i < childrenNum; i++) {
            DFS(nodes[root].children.get(i), depth + 1);
        }
    }
	// 使用BFS 求解
    static void BFS(int root) {
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {

            int size = queue.size() ;
            num = size ; // 最后一次队列中的元素个数就是最后一层的元素个数
            while (size !=0){
                int node = queue.poll() ;
                int childrenNum = nodes[node].children.size(); // 为了避免在循环中每次都进行个数计算
                for(int i =0;i<childrenNum ;i++){
                    queue.offer(nodes[node].children.get(i)) ;
                }
                size -- ;
            }
           maxDepth ++ ;
        }
      
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值