zoukankan      html  css  js  c++  java
  • Monster Hunter 树形DP 南京ICPC 2020

    Monster Hunter 树形DP

    题目大意:

    给你一棵n个节点的树,每一个节点有一个怪兽,这个怪兽有一个生命值。

    消灭一个怪兽:

    • 前提:这个节点的直接父亲节点怪兽已经被消灭
    • 代价:这个节点的权值+它所有的子节点怪兽的生命值之和

    特别的是,你可以使用魔咒,每一次魔咒使用,你可以直接消灭一个怪兽,而不会有任何的花费,也不需要任何的前提。

    m = 0,1,2,3...,n。问使用m次魔咒,消灭所有怪兽的最小的代价是多少?

    题解:

    这个题目一开始我们队想用贪心,后来发现贪心是错误的,然后就尝试使用dp来解决。

    (dp[u][j][0/1]) :表示u这个节点,使用了 j 次魔法,0表示u节点没有使用魔法,1表示有使用魔法。

    这个转移我写了很久,一直写不出来,后来发现是需要一个辅助数组,每次需要辅助数组的题目我好像都没有写出来,感觉好可惜。

    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    const int maxn = 2e3+10;
    typedef long long ll;
    int cnt,head[maxn],to[maxn<<1],nxt[maxn<<1];
    ll hp[maxn],dp[maxn][maxn][2];
    void init(int n){
        cnt = 0;
        for(int i=0;i<=n+10;i++) {
            head[i] = 0;
            for(int j=0;j<=n+10;j++){
                dp[i][j][0] = dp[i][j][1] = 0;
            }
        }
    }
    void add(int u,int v){
        ++cnt,to[cnt] = v,nxt[cnt] = head[u],head[u] = cnt;
    }
    int siz[maxn];
    ll tmp[maxn][2];
    void dfs(int u){
        siz[u] = 1;
        for(int i=head[u];i;i=nxt[i]){
            int v = to[i];
            dfs(v);
            memset(tmp,inf64,sizeof(tmp));
            for(int j=0;j<=siz[u];j++){
                for(int k=0;k<=siz[v];k++){
                    tmp[j+k][0] = min(tmp[j+k][0],dp[u][j][0]+dp[v][k][0]+hp[v]);
                    if(k>0) tmp[j+k][0] = min(tmp[j+k][0],dp[u][j][0]+dp[v][k][1]);
                    if(j>0) tmp[j+k][1] = min(tmp[j+k][1],dp[u][j][1]+dp[v][k][0]);
                    if(j>0&&k>0) tmp[j+k][1] = min(tmp[j+k][1],dp[u][j][1]+dp[v][k][1]);
    //                printf("u = %d v = %d j = %d k = %d 
    ",u,v,j,k);
    //                printf("tmp[%d][%d]=%lld tmp[%d][%d]=%lld
    ",j+k,0,tmp[j+k][0],j+k,1,tmp[j+k][1]);
                }
            }
            for(int j=0;j<=siz[u]+siz[v];j++) {
                dp[u][j][0] = tmp[j][0],dp[u][j][1] = tmp[j][1];
    //            printf("dp[%d][%d][%d]=%lld dp[%d][%d][%d]=%lld
    ",u,j,0,dp[u][j][0],u,j,1,dp[u][j][1]);
            }
            siz[u]+=siz[v];
        }
        for(int i=0;i<=siz[u];i++) {
            dp[u][i][0]+=hp[u];
    //        printf("u = %d dp[%d][%d][%d] = %lld dp[%d][%d][%d]=%lld
    ",u,u,i,0,dp[u][i][0],u,i,1,dp[u][i][1]);
        }
    }
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            int n;
            scanf("%d",&n);init(n);
            for(int i=2,x;i<=n;i++){
                scanf("%d",&x);
                add(x,i);
            }
            for(int i=1;i<=n;i++) scanf("%lld",&hp[i]);
            dfs(1);
            for(int i=0;i<=n;i++){
                printf("%lld",min(dp[1][i][0],dp[1][i][1]));
                if(i==n) printf("
    ");
                else printf(" ");
            }
        }
    }
    
    
  • 相关阅读:
    知识点整理
    NGINX 内存池有感
    NGINX怎样处理惊群的
    NGINX 定时器
    制作linux内核安装包
    ES6变量的解构赋值
    jquery uploadify上传插件用法心得
    【转贴】J2EE中的13种技术规范
    【转帖】Servlet 3.0 新特性详解
    汉诺塔问题的一个C#实现
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/14345610.html
Copyright © 2011-2022 走看看