zoukankan      html  css  js  c++  java
  • poj1155 TELE (树上分组背包)

    题目链接:https://vjudge.net/problem/POJ-1155

    题意:给定一颗以1为根的边权树,有n个结点,其中m个叶子结点,每个叶子结点有一个价值。要求从m个叶子结点中选最多的结点,费用是从根节点到叶子结点的边权和,价值是所有选中的叶子结点价值和。

    思路:

      树上分组背包。用dp[u][j]表示对于结点u的子树,选j个叶子结点的最大利润,即价值-花费。因为对u的每个子结点v1,v2,v3,在v1的子树中最多选择一种方案,不可能重叠选择,所以是分组背包。先处理出num[u],表示结点u的子树中叶子结点的个数。

      那么对于叶子结点u:dp[u][j]=a[u](a[u]是叶子结点u的价值)

        对于非叶子结点u:dp[u][j]=max(dp[u][j] , dp[u][j-k]+dp[v][k]-len),其中j是最大容量,k是枚举的容量。

      dp数组初始化为负无穷,因为一条利润为负数的方案在后面也可以和另一条利润正的方案合并,最终利润仍为正。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    const int maxn=3005;
    const int ninf=0xcfcfcfcf;
    int n,m,head[maxn],a[maxn],cnt,dp[maxn][maxn],num[maxn];
    
    struct node{
        int v,w,nex;
    }edge[maxn];
    
    void adde(int u,int v,int w){
        edge[++cnt].v=v;
        edge[cnt].w=w;
        edge[cnt].nex=head[u];
        head[u]=cnt;
    }
    
    void dfs(int u){
        if(!head[u]){
            dp[u][1]=a[u];
            num[u]=1;
            return;
        }
        for(int i=head[u];i;i=edge[i].nex){
            int v=edge[i].v;
            dfs(v);
            num[u]+=num[v];
        }
        for(int i=head[u];i;i=edge[i].nex){
            int v=edge[i].v;
            for(int j=num[u];j>=1;--j)
                for(int k=1;k<=min(j,num[v]);++k)
                    if(dp[u][j-k]!=ninf&&dp[v][k]!=ninf)
                        dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-edge[i].w);
        }
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                dp[i][j]=ninf;
        for(int i=1;i<=n-m;++i){
            int k,t1,t2;
            scanf("%d",&k);
            for(int j=1;j<=k;++j){
                scanf("%d%d",&t1,&t2);
                adde(i,t1,t2);
            }
        }
        for(int i=n-m+1;i<=n;++i)
            scanf("%d",&a[i]);
        dfs(1);
        for(int i=m;i>=0;--i)
            if(dp[1][i]>=0){
                printf("%d
    ",i);
                break;
            }
        return 0;
    }
  • 相关阅读:
    Charles网络工具
    查找最长子串的长度(不重复字符)
    KMP算法
    java并发编程实战:第十四章----构建自定义的同步工具
    java并发编程实战:第十二章---并发程序的测试
    java并发编程实战:第二章----线程安全性
    java并发编程实战:第三章----对象的共享
    java并发编程实战:第四章----对象的组合
    java并发编程实战:第五章----基础构建模块
    java并发编程实战:第六章----任务执行
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/11434942.html
Copyright © 2011-2022 走看看