zoukankan      html  css  js  c++  java
  • BZOJ 3090: Coci2009 [podjela] (树形背包)

    3090: Coci2009 [podjela]

    Time Limit: 3 Sec  Memory Limit: 128 MB
    Submit: 45  Solved: 31
    [Submit][Status][Discuss]

    Description

    有 N 个农民, 他们住在 N 个不同的村子里. 这 N 个村子形成一棵树.
    每个农民初始时获得 X 的钱.
    每一次操作, 一个农民可以从它自己的钱中, 取出任意数量的钱, 交给某个相邻村子的农民.

    对于每个农民给定一个值 v_i, 求
        (1) 最少需要多少次操作, 使得每个农民最终拿到的钱 >= 给定的值.
       

    Input

        第1行: 一个整数 N (1 <= N <= 2000)
        第2行: 一个整数 X (0 <= X <= 10000)
        第3行: N 个整数, 表示 v_i. 保证所有 v_i 的和 <= N * X
        第4..N+2行: 每行两个 1..N 的数, 表示树上的一条边. 边是双向的.

    Output

        第1行: 一个整数, 最少需要的操作次数

    Sample Input

    6
    15
    10 20 18 16 6 16
    1 4
    4 5
    4 6
    6 2
    5 3

    Sample Output

    5
     
     
    解题思路
    树形背包,设dp[x][i]表示以x为根的子树,操作了i次,目前能给出/索要的钱数。u为x的儿子,如果dp[u][k]<0,说明这条边必须连,dp[x][j+k+1]=dp[x][j]+dp[u][k],否则可以不连,dp[x][j+k]=dp[x][j]
     
     
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    const int MAXN = 2005;
    const int inf = -0x3f3f3f3f;
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
    
    int n,st,val[MAXN],head[MAXN],cnt,dp[MAXN][MAXN],siz[MAXN];
    int to[MAXN<<1],nxt[MAXN<<1];
    
    inline void add(int bg,int ed){
        to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
    }
    
    void dfs(int x,int fa){
        int u,k,tmp;dp[x][0]=st-val[x];siz[x]=1;
        for(register int i=head[x];i;i=nxt[i]){
            u=to[i];if(u==fa) continue;dfs(u,x);
            for(k=0;k<siz[u] && dp[u][k]==inf;k++);
            for(register int j=siz[x];j<siz[x]+siz[u];j++) dp[x][j]=inf;
            for(register int j=siz[x]-1;j>=0;j--){
                tmp=dp[x][j];dp[x][j]=inf;
                if(tmp==inf) continue;
                for(register int o=k;o<siz[u];o++) {
                    if(dp[u][o]==inf) continue;
                    dp[x][j+o+1]=max(dp[x][j+o+1],tmp+dp[u][o]);
                    if(dp[u][o]<0) continue;
                    dp[x][j+o]=max(dp[x][j+o],tmp);
                }
            }
            siz[x]+=siz[u];
        }
    }
    
    int main(){
        n=rd(),st=rd();int x,y;
        for(int i=1;i<=n;i++) val[i]=rd();
        for(int i=1;i<n;i++){
            x=rd(),y=rd();
            add(x,y),add(y,x);
        }
        dfs(1,0);    
        for(int i=0;i<n;i++) if(dp[1][i]>=0) {
            printf("%d",i);break;    
        }
        return 0;
    }
    View Code
     
  • 相关阅读:
    WindowsServer 2016激活
    selenium浏览器复用与原理分析
    react脚手架: 配置代理
    网络请求方式
    Java: Excel导入导出
    react 组件通信方式
    react: reactrouterdom
    react: 高阶函数及函数柯里化
    react: 事件处理
    react: 生命周期
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9726581.html
Copyright © 2011-2022 走看看