[树上DP] UVa12186 工人的请愿书(小数处理)

题目

这里写图片描述

思路

(本题是直接给了有向树,所以不用像求树的最大独立集,重心,最长路径这样的无根转有向)
1.状态定义:d(u),让u给上级发信最少需要多少个工人。
2.初状态: { d ( i ) = 1   |   i   i s   a   w o r k e r }
3.答案:d(0)
4.状态转移方程:

d ( i ) = j s o n s [ i ] , k = 0 k < c d ( j )   | s o n s [ i ] d  

c = ( g T 1 ) / 100 + 1 , g i

(注意此处求c时的小数处理)

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;

const int maxn = 100000 + 100;
int N, T, d[maxn];
vector<int> sons[maxn];  // sons[i]为结点i的儿子们

int dp(int u) {
    if (sons[u].empty()) return 1;
    vector<int> d;
    for (vector<int>::iterator iter = sons[u].begin(); iter != sons[u].end(); ++iter)
        d.push_back(dp(*iter));
    sort(d.begin(), d.end());
    int c = (sons[u].size()*T - 1) / 100 + 1;   // 此处的减一加一适合于出现小数的情况
    int ans = 0;
    _for(i, 0, c) ans += d.at(i);
    return ans;
}

int main() {
    while (scanf("%d%d", &N, &T) == 2 && N && T) {
        int u;
        _rep(i, 0, N) sons[i].clear();
        _rep(i, 1, N) {
            scanf("%d", &u);
            sons[u].push_back(i);
        }
        printf("%d\n", dp(0));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/80982169