★☆★cf 1059E Split the Tree

http://codeforces.com/problemset/problem/1059/E

想法非常的新颖,以为是个树形dp,你根据子节点的情况来决定父节点是跟随某个子节点继续向上,还是自己独立开始一段新的path。

但是!!!想想这个问题的性质,有个疑问:局部最优会导致全局最优吗?答案是肯定的,所以,直接上贪心!

我们来看这个贪心的性质,就是有两个叶子节点a,b,他们有公共的父节点c,沿着a,b一直向上寻找(不同问题有不同寻找方向,一般从下网上,但别被拘束),直到长度或者w超限,假设a能到c上面的一个节点,b却能到c上面的三个节点,那么这三个节点划分到b的path为最优,因为我总不至于能包含却不去包含他们的。

就是说,即便先选了a,向上追溯并染色到了c上1点,后选了b,向上追溯并染色到了c上3点,我们不就是等于说,a的后半段不跟a了,改成属于b的path。因为我们总是改变后半段的归属,右总是从叶子节点开始,所以这种贪心总是能得到更好的结果,而且保证最好的结果是总能出现的。

下面的代码是可以hack的,因为没有保证每次都是从叶子节点开始寻找,只要做一次bfs对层次作排序就能保证son总是出现father后面,就可以了,但是我没改。

code:

#include<iostream>

using namespace std;
int n,L,nowl,ans,now,i,mp[100001],fa[100001];
long long S,a[100001],nows,mx;
int main(){
    scanf("%d%d%lld",&n,&L,&S);
    for(i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        mx=max(mx,a[i]);
    }
    if(mx>S){
        puts("-1");
        return 0;
    }
    for(i=2;i<=n;i++)scanf("%d",&fa[i]);
    for(i=n;i;i--)
        if(!mp[i]){
            ans++;nowl=L;nows=S;now=i;
            while(now&&nowl>0&&nows>=a[now]){
                mp[now]=1;nowl--;nows-=a[now];
                now=fa[now];
            }
        }
    printf("%d",ans);
}

猜你喜欢

转载自www.cnblogs.com/waldenlake/p/9750249.html