1079 Total Sales of Supply Chain (25 分)
题目传送门:1079 Total Sales of Supply Chain (25 分)
一、题目大意
商品销售链上有供应商、经销商、零售商,供应商以原价P将商品卖给经销商或者零售商,而经销商将会价格提高r%再卖给下一级的经销商或者零售商。零售商从上一级买到商品后,也会将价格提高r%,然后直接卖给用户。题目保证每一级的人都只有一个上级。
转化成模型就是一棵有根多叉树,其中供应商是树根,经销商是非叶子节点,零售商是叶子节点。题目要求零售商(叶子节点)的收益,也就是到所有零售商这一级时,它的售价*数量的和。
二、解题思路
这道题用DFS或者BFS都好写,不过N达到10^5, 我怕用DFS写会超时或者栈溢出,所以用BFS。由于惯性思维之前写BFS时用优先级队列较多,其实本题不需要用优先级队列,直接用普通队列即可。因为所有的叶子节点都得访问到,且所有节点的价格均为它父节点价格的(1+r%)
倍,所以其实直接使用普通队列模拟也是可以的,我用优先级队列多此一举了。
先将根节点入队,根节点的价格是p(我刚开始忽略了这一点,所以在第二组数据中n为1时WA了,修正了此处后就AC了)。然后遍历队列的头,并且依次出队。判断如果队列的头结点是叶子节点,则统计售价*数量,如果不是叶子节点,则判断它有哪些子节点,让他的子节点的p在当前头结点的p基础上乘(1+r%),然后入队
注意用一个book数组标记结点的访问情况,保证结点不要被重复访问。
三、AC代码
#include<bits/stdc++.h>
using namespace std;
struct Node
{
int id, leaf, tot;// leaf为1表示是叶子节点,为0表示是非叶子节点。tot表示当leaf时产品的数量
double p;
bool operator<(const Node & that)const{
if(p != that.p)
return p < that.p;
return id < that.id;
}
};
int main(){
int n;
double p, r;
scanf("%d %lf %lf", &n, &p, &r);
vector<int>M[n];// 存储每个节点有哪些子节点
vector<Node>nodes(n);// 存储每个节点的信息
for(int i = 0; i < n; i++){
int t;
scanf("%d", &t);
Node node;
node.id = i;
if(t){
while(t--){
int x;
scanf("%d", &x);
M[i].push_back(x);
}
node.leaf = 0;
}else{
cin >> node.tot;
node.leaf = 1;
}
nodes[i] = node;
}
nodes[0].p = p;
vector<int>book(n);
priority_queue<Node>Q;// 本题其实只需要按层遍历即可,没有优先级要求,不用priority_queue就只用普通的queue也行
Q.push(nodes[0]);
double result = 0;
while(Q.size()){
Node head = Q.top();
Q.pop();
if(book[head.id])continue;
if(head.leaf){
result += head.tot * head.p;
}
book[head.id] = 1;
for(auto i: M[head.id]){
Node node = nodes[i];
node.p = head.p*(1+r/100);
Q.push(node);
}
}
printf("%.1f\n", result);
}