一开始用的是模拟的方法,因此花的时间有些多,看了其他人的才知道可以用深度搜索来做。
如果用模拟的方法需要注意一点:徒弟的序号可能会比师父的序号靠前
例如测试用例中加粗部分:
10 18.0 1.00
3 2 3 5
1 9
1 4
1 7
0 7
2 6 1
1 8
0 9
0 4
0 3
因此,对于这些应该从后面人的功力开始算起的点,需要先压入栈中:栈顶是最后压入的,而它的徒弟在它下面,即在它之后算。
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
const int MAX = 1e5 + 5;
struct Person {
double power; //功力值
vector<int> tudi; //此人的徒弟
int N; //得到弟子的功力加成倍数
};
Person p[MAX];
stack<pair<int,int> > waiting; //暂未处理功力的徒弟
double get_power(int x,double r) { //求功力
return (100 - r) * p[x].power / 100;
}
int main() {
int N;
double Z,r,ans=0;
cin >> N >> Z >> r;
p[0].power = Z;
for (int i = 0; i < N ; i++) {
int n,x;
cin >> n;
for (int j = 0; j < n; j++) {
cin >> x;
p[i].tudi.push_back(x);
if (p[i].power > 0.001) { //师父的功力已知,因此可算得徒弟功力
p[x].power= get_power(i, r);
}
else { //否则压入栈中
waiting.push({ i, x });
}
}
if (n == 0) {
cin>>p[i].N;
}
}
//处理未处理的徒弟
while (!waiting.empty()) {
pair<int, int> temp = waiting.top();
waiting.pop();
p[temp.second].power = get_power(temp.first, r);
}
//求得道者的功力和
for (int i = 0; i < N; i++) {
if (p[i].N > 0) {
ans += p[i].power * p[i].N;
}
}
cout << (int)ans;
return 0;
}
采用深度搜索递归的方式代码更简洁!
#include<iostream>
#include<vector>
using namespace std;
const int MAX = 1e5 + 5;
vector<int> Map[MAX];
int N;
double Z, r, ans;
int other[MAX];
void DFS(int n,double power) {
if (Map[n].size() == 0 && other[n] > 0) {
ans += power * other[n];
return;
}
for (int i = 0; i < Map[n].size(); i++) {
DFS(Map[n][i], power * r);
}
}
int main() {
cin >> N >> Z >> r;
int M;
r = (100 - r) / 100; //衰减值
for (int i = 0; i < N; i++) {
cin >> M;
for (int j = 0; j < M; j++) {
int x;
cin >> x;
Map[i].push_back(x);
}
if (M == 0) cin >> other[i];
}
DFS(0, Z);
cout << (int)ans;
return 0;
}