zoukankan      html  css  js  c++  java
  • HDU4044 GeoDefense(有点不一样的树上背包)

    题目大概说一棵n个结点的树,每个结点都可以安装某一规格的一个塔,塔有价格和能量两个属性。现在一个敌人从1点出发但不知道他会怎么走,如果他经过一个结点的塔那他就会被塔攻击失去塔能量的HP,如果HP小于等于0敌人就挂了。任务就是在总花费不超过m的条件下在各个结点安装塔,求能预防的敌人的HP的最大值。

    状态容易表示,dp[u][m]表示在结点u为根的子树中花费m能预防的最大的HP

    转移显然又是树上背包了,不过略麻烦,想清楚的话还是能比较快地写完:

    • u子树从它孩子结点的子树的最小值中转移过来,因为各个孩子都必须选我用了一个临时数组存值转移完后更新回去
    • 这样处理完u的各个子树,再用一遍背包加上u结点本身能建的塔,就是dp[u]状态的值了

    WA了一发,因为同一价格不同能量没考虑到。。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 #define MAXN 1111
     6 struct Edge{
     7     int v,next;
     8 }edge[MAXN<<1];
     9 int NE,head[MAXN];
    10 void addEdge(int u,int v){
    11     edge[NE].v=v; edge[NE].next=head[u];
    12     head[u]=NE++;
    13 }
    14 int m,mat[MAXN][222];
    15 int d[MAXN][222],tmp[222];
    16 void dp(int u,int fa){
    17     d[u][0]=0;
    18     bool first=1;
    19     for(int i=head[u]; i!=-1; i=edge[i].next){
    20         int v=edge[i].v;
    21         if(v==fa) continue;
    22         dp(v,u);
    23         if(first){
    24             first=0;
    25             for(int j=0; j<=m; ++j) d[u][j]=d[v][j];
    26             continue;
    27         }
    28         memset(tmp,-1,sizeof(tmp));
    29         for(int j=0; j<=m; ++j){
    30             for(int k=0; j+k<=m; ++k){
    31                 tmp[j+k]=max(tmp[j+k],min(d[u][j],d[v][k]));
    32             }
    33         }
    34         for(int j=0; j<=m; ++j) d[u][j]=tmp[j];
    35     }
    36     for(int i=m; i>=0; --i){
    37         for(int j=0; j<=i; ++j){
    38             if(d[u][i-j]==-1 || mat[u][j]==-1) continue;
    39             d[u][i]=max(d[u][i],d[u][i-j]+mat[u][j]);
    40         }
    41     }
    42 }
    43 int main(){
    44     int t,n,a,b,c;
    45     scanf("%d",&t);
    46     while(t--){
    47         NE=0;
    48         memset(head,-1,sizeof(head));
    49         scanf("%d",&n);
    50         for(int i=1; i<n; ++i){
    51             scanf("%d%d",&a,&b);
    52             addEdge(a,b); addEdge(b,a);
    53         }
    54         memset(mat,-1,sizeof(mat));
    55         scanf("%d",&m);
    56         for(int i=1; i<=n; ++i){
    57             scanf("%d",&a);
    58             while(a--){
    59                 scanf("%d%d",&b,&c);
    60                 mat[i][b]=max(mat[i][b],c);
    61             }
    62         }
    63         memset(d,-1,sizeof(d));
    64         dp(1,1);
    65         int res=0;
    66         for(int i=0; i<=m; ++i) res=max(res,d[1][i]);
    67         printf("%d
    ",res);
    68     }
    69     return 0;
    70 }
  • 相关阅读:
    2019牛客暑期多校赛(第四场)
    单调栈求左右第一个比该数大(小)的位置
    带修莫队板子
    普通莫队算法
    2019牛客暑期多校赛(第三场)B-求01串中的最长01数量相等的子串和子序列
    2019牛客暑假多校赛(第二场) F和H(单调栈)
    网络文件系统nfs
    rsync详解
    逻辑卷LVM
    crontab定时任务
  • 原文地址:https://www.cnblogs.com/WABoss/p/5336152.html
Copyright © 2011-2022 走看看