您的位置:首页 > 其它

UVa 12186 Another Crisis(树形DP)

2015-02-07 21:34 411 查看
题目链接:http://arena.acmclub.com/problem.php?id=16295

题意:

给出一个树状关系图,公司里只有一个老板编号为0,其他人员从1开始编号。除了老板,每个人都有一个直接上司,没有下属的员工成为工人。工人们想写一份加工资的请愿书,只有当不少于员工的所有下属的T%人递交请愿书后,该员工才会将请愿书递交给他的直接上级。输出能递交到老板处,最少需要多少工人写请愿书。

分析:

d(u)表示让u给上级发信最少需要多少个工人。假设u有k个子节点,则至少需要c = (k*T - 1) / 100 + 1 个直接下级发信给他才行。把所有子节点的d从小到大排序,前c个和就是d(u)。

如何理解这一步?设 x = 结点的人数*百分比。根结点个子结点,前c个x值最小的结点的和,就是最后的结果。根结点的子结点,同样需要满足,前c个x值最小的结点的和,才能签字。同理,根结点的孙结点、子孙结点……一直到最后一层,最后一层称为叶结点,即没有子结点,当程序访问到这一层的时候,直接返回1,即叶结点本身。

用深度优先的方式,求出根结点的每个子结点的d值,将前c个最小的d值相加,就能得出结果。建议画图辅助理解,详见代码与注释。

所求答案就是d(0)。
这里考虑到浮点误差,所以才将 k*T / 100 写为 (k*T - 1) / 100 + 1 , 这样一来c就是 不少于k的T%的最小整数。

输入:

第一行输入n(员工数)、 t(百分比)。

第二行输入编号从1到n的员工的直接上司。

输出:

输出最少需要的人数。

本菜鸡的一点思考,如有不正确的地方,欢迎指教。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main16295 {
static int max = 100000 + 10;
static ArrayList[] sons = new ArrayList[max];
static int n, t;

public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNextInt()) {
n = in.nextInt();
t = in.nextInt();
if (n == 0 && t == 0)
break;
for (int i = 0; i <= n; i++) {
sons[i] = new ArrayList();
}
for (int i = 1; i <= n; i++) {
int x = in.nextInt();//每个上司。
sons[x].add(i);//添加每个上司的直系下属。
}
System.out.println(dp(0));
}
}

public static int dp(int u) {
if (sons[u].isEmpty())//访问到叶结点时,返回它本身,即1。
return 1;
int k = sons[u].size();
ArrayList d = new ArrayList();//d(u)表示让u给上级发信最少需要多少个工人。
for (int i = 0; i < k; i++) {
d.add(dp((int) sons[u].get(i)));//这里用深度优先进行添加。
}
Object[] a = d.toArray();//由于ArrayList没有直接排序功能
Arrays.sort(a);//故先转为Object[],再排序。
int c = (k * t - 1) / 100 + 1;
int ans = 0;
for (int i = 0; i < c; ++i) {
ans += (int) a[i];//前c个最小的d值就是所求。
}
return ans;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: