微软2017年预科生计划在线编程笔试第二场-#1500 : EL SUENO

http://hihocoder.com/problemset/problem/1500

题意理解:一棵树,父亲只有在直接儿子被干掉的权重和大于某个数才能都被干掉,并且干掉一个点需要若干时间。权重《=20000, 节点《=2000,可以每一个节点都用裸的01背包做,注意背包容量可以超过,最后取min

急转弯:数据范围小,可以裸着做,另外注意min的取法。

算法:无

数据结构:树,但是和树的数据结构没有关系,只是用到了树的先考虑儿子,再考虑父亲的遍历(dfs)


注:python版本t了。。尴尬。。有好的优化希望能告诉我!


#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;

const int maxn = 2000 + 100;
const int MAXK = 20000 + 100;
const int INF = 1e7;

int need[maxn], have[maxn], tim[maxn];
int n, rt;
vector<int> G[maxn];

int dfs(int u) {
    if(G[u].size() == 0) return tim[u];
    int f[MAXK];
    f[0] = 0;
    for(int i = 1; i < MAXK; i++) f[i] = INF;
    for(int i = 0; i < G[u].size(); i++){
        int v = G[u][i];
        int t = dfs(v);
        for(int j = need[u] - 1; j >= 0; j--) {
            int no = min(MAXK - 1, j + have[v]);
            f[no] = min(INF, min(f[no], f[j] + t));
        }
    }
    int res = INF;
    for(int i = need[u]; i < MAXK; i++) res = min(res, f[i]);
    return res + tim[u];
}

int main() {
    scanf("%d", &n);
    rt = 1;
    for(int i = 1; i <= n; i++) G[i].clear();
    for(int i = 1; i <= n; i++) {
        int a, b, c, d;
        scanf("%d%d%d%d", &a, &b, &c, &d);
        if(a == 0){
            rt = i;
        } else{
            G[a].push_back(i);
        }
        need[i] = b;
        have[i] = c;
        tim[i] = d;
    }
    int res = dfs(rt);
    if(res < INF) printf("%d\n", res);
    else printf("-1");
}
from __future__ import print_function
#
#

'python for tree and easy dp'

__author__ = 'hjkruclion'

import sys

def read_int():
    return list(map(int, sys.stdin.readline().split()))

MAXN = 20000 + 10
INF = int(1e7)
MAXP = 2000 + 100

G = [[]for _ in range(MAXP)]
# need = np.zeros([MAXP], np.int)
# have = np.zeros([MAXP], np.int)
# time = np.zeros([MAXP], np.int)

need = [0 for _ in range(MAXP)]
have = [0 for _ in range(MAXP)]
time = [0 for _ in range(MAXP)]
dp = [0 for _ in range(MAXP)]
f = [0 for _ in range(MAXN + 10)]

rt = 1
N = read_int()[0]
for i in range(1, N + 1):
    fa, iN, ip, c = read_int()
    if fa != 0:
        G[fa].append(i)
    else:
        rt = i
    need[i] = iN
    have[i] = ip
    time[i] = c


def dfs(u):
    if len(G[u]) == 0:
        return time[u]
    # f = np.zeros([MAXN + 10], np.int)
    for i in range(len(G[u])):
        v = G[u][i]
        dp[v] = dfs(v)
    global f
    f[0] = 0
    for i in range(1, MAXN):
        f[i] = INF
    for i in range(len(G[u])):
        v = G[u][i]
        t = dp[v]
        for j in reversed(range(need[u])):
            no = min(need[u], j + have[v])
            f[no] = min(INF, min(f[no], f[j] + t))
    res = f[need[u]]
    return min(INF, res + time[u])

res = dfs(rt)
if res < INF:
    print(res)
else:
    print('-1')



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值