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);
}