代码分递归和非递归两个版本。
递归版本是直接参考紫书的。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=100000+5;
int n,T;
vector<int> sons[maxn];
int dp(int u) {
if (sons[u].empty()) return 1;
vector<int> d;
for (int i=0; i<sons[u].size(); i++)
d.push_back(dp(sons[u][i]));
sort(d.begin(), d.end());
int c = (sons[u].size()*T-1)/100 + 1;
int ans = 0;
for (int i=0; i<c; i++)
ans+=d[i];
return ans;
}
int main()
{
int boss;
while(scanf("%d%d", &n, &T)==2 && n) {
for (int i=0; i<=n; i++)
sons[i].clear();
for (int i=1; i<=n; i++) {
scanf("%d", &boss);
sons[boss].push_back(i);
}
cout<<dp(0)<<endl;
}
return 0;
}
有几点要注意:
1) c=(KT-1)/100+1 是表示不小于KT/100的最小整数。比如说KT=33, 那么KT/100=0, c=1。KT=1, KT/100=0, c=1。
那么为何不直接用KT/100+1呢?因为如果KT/100刚好为1的话,那么c=2,但实际上c应该等于1。
2)初始化sons[]的时候i从0开始,因为老板的sons也要初始化为0。但给sons[]赋值的时候i从1开始,比如说0,3,5,说明员工1的老板是0,员工2的老板是3,员工3的老板是5。
3) 因为题目说要最少所需的员工签字,所以要对d数组sort,找出前面c个最小的数值来。
非递归版本是我写的,用栈来实现。这个代码可能不是最优,因为还加上了parent[]数组,不过好歹还是被接受了。如果大家有更好的欢迎留言。
#include<iostream>
#include<vector>
#include<algorithm>
#include <stack>
using namespace std;
const int maxn=100000+5;
int n,T;
vector<int> sons[maxn];
int parent[maxn] = {0};
stack<int> s;
int ans[maxn] = {0};
int dp_non_recursion() {
vector<int> d;
//从老板开始,依次将儿子压栈
s.push(0);
for (int i=0; i<n; i++)
for (int j=0; j<sons[i].size(); j++)
s.push(sons[i][j]);
while(!s.empty()) {
d.clear();
int t = s.top();
s.pop();
if (sons[t].size()==0)
ans[t]=1;
else{
for (int i=0; i<sons[t].size(); i++) {
d.push_back(ans[sons[t][i]]);
}
sort(d.begin(), d.end());
int c = (sons[t].size()*T-1)/100 + 1;
for (int i=0; i<c; i++)
ans[t]+=d[i];
}
}
return ans[0];
}
int main()
{
int boss;
while(scanf("%d%d", &n, &T)==2 && n) {
for (int i=0; i<=n; i++) {
sons[i].clear();
ans[i]=0;
}
for (int i=1; i<=n; i++) {
scanf("%d", &boss);
parent[i]=boss;
sons[boss].push_back(i);
}
cout<<dp_non_recursion()<<endl;
}
return 0;
}
注意不管是递归还是非递归,我们都不需要用到vis[],因为每个节点都刚好处理一次,没有重复访问的情况。