树上的动态规划学习2 - Another Crisis (Uva12186)

代码分递归和非递归两个版本。

递归版本是直接参考紫书的。

#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[],因为每个节点都刚好处理一次,没有重复访问的情况。

猜你喜欢

转载自blog.csdn.net/roufoo/article/details/79205789