zoukankan      html  css  js  c++  java
  • 树形dp

    1.codeforces 816 E. Karen and Supermarket

     题意:有n件商品,每件有价格ci,优惠券di,对于i>=2,使用di的条件为:xi的优惠券需要被使用,问初始金钱为b时 最多能买多少件商品? n<=5000,ci,di,b<=1e9

    思路:

    根据限制连边 转化为背包问题
    dp[i][j][0/1] 表示以i为根的树中选了j件,第i件打不打折的最优值。
    转移时枚举儿子选了多少 他就选了j减多少
    最后统计答案 第一个小于等于限制钱数的就是。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 5007
    #define inf 0x3f3f3f3f
    
    using namespace std;
    int n,b,ans,cnt,x;
    int head[N],dp[N][N][2],siz[N],pr[N],pd[N];
    struct edge
    {
        int v,next;
    }e[N<<1];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    inline void add(int u,int v)
    {
        e[cnt].v=v;e[cnt].next=head[u];head[u]=cnt++;
    }
    
    void dfs(int u)
    {
        siz[u]=1;
        dp[u][0][0]=0;
        dp[u][1][0]=pr[u];
        dp[u][1][1]=pr[u]-pd[u];
        for(int i=head[u];~i;i=e[i].next)
        {
            int v=e[i].v; dfs(v);
            for(int j=siz[u];j>=0;j--)
            {
                for(int k=1;k<=siz[v];k++)
                {
                    dp[u][j+k][0]=min(dp[u][j+k][0],dp[u][j][0]+dp[v][k][0]);
                    dp[u][j+k][1]=min(dp[u][j+k][1],dp[u][j][1]+dp[v][k][0]);
                    dp[u][j+k][1]=min(dp[u][j+k][1],dp[u][j][1]+dp[v][k][1]);
                }
            }siz[u]+=siz[v];
        }
    }
    
    int main()
    {
        n=read();b=read();
        memset(dp,0x3f,sizeof dp);
        memset(head,-1,sizeof head);
        for(int i=1;i<=n;i++)
        {
            pr[i]=read();pd[i]=read();
            if(i!=1)
            {
                x=read();add(x,i);
            }
        }dfs(1);
        for(int i=n;i>=0;i--)
        {
            if(dp[1][i][1]<=b || dp[1][i][0]<=b)
            {
                ans=i;
                break;
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    Code

     

    2.洛谷P1272

    题意:一棵树上要断掉大小为P的子树,求最少断掉边数

    思路:

    显然树形dp
    dp[i][j]:i为根断掉子树大小为j最小边数
    初始化dp[u][1]=1的度数
    转移时枚举当前点断掉多少,算出连到的儿子断掉多少
    因为由儿子转移过来,他们之间的连边不能断
    但是转移时断掉了两次,所以答案减2

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 151
    #define inf 0x7f7f7f7f
    
    using namespace std;
    int dp[N][N],head[N],d[N];
    int n,m,ans,cnt;
    struct node
    {
        int u,v,next; 
    }e[N<<1];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    inline void add(int u,int v)
    {
        e[++cnt].v=v;e[cnt].next=head[u];head[u]=cnt;
    }
    
    void dfs(int u,int fa)
    {
        dp[u][1]=d[u];
        for(int i=head[u];i;i=e[i].next)
        {
            if(e[i].v!=fa)
            {
                dfs(e[i].v,u);
                for(int j=m;j>=1;j--)
                  for(int k=1;k<=j;k++)
                    dp[u][j]=min(dp[u][j],dp[e[i].v][k]+dp[u][j-k]-2);
            }
        }ans=min(ans,dp[u][m]);
    }
    
    int main()
    {
        int x,y;
        memset(dp,1,sizeof dp);
        n=read();m=read();
        for(int i=1;i<n;i++)
        {
            x=read();y=read();
            add(x,y);add(y,x);
            d[x]++;d[y]++;
        }
        ans=inf;
        dfs(1,0);
        printf("%d
    ",ans);
        return 0;
    }
    Code

     

    3.洛谷P3174  https://www.luogu.org/problemnew/show/P3174

    题解:https://www.cnblogs.com/L-Memory/p/9766728.html

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 300007
    
    using namespace std;
    int f[N],head[N],son[N];
    int n,m,k,ans,maxx;
    struct edge
    {
        int to,net;
    }e[N<<1];
    
    inline void add(int u,int v)
    {
        e[++k].to=v;e[k].net=head[u];head[u]=k;
    }
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    void dfs(int u,int fa)
    {
        int v,bigx=0,lowx=0;
        for(int i=head[u];i;i=e[i].net)
        {
            v=e[i].to;
            if(v!=fa)
            {
                dfs(v,u);
                if(f[v]>lowx)//维护最大链与次大链 
                {
                    if(f[v]>bigx)lowx=bigx,bigx=f[v];
                    else lowx=f[v];
                }
                f[u]=max(f[u],f[v]+son[u]-1);
            }
        }
        ans=max(ans,lowx+bigx+son[u]-1);//(-1是因为根节点重复加了) 
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int u,v;
            u=read();v=read();
            add(u,v);add(v,u);
            son[u]++;son[v]++; 
        }
        for(int i=1;i<=n;i++)f[i]=1;
        dfs(1,0);
        printf("%d",ans);
    }
    Code

    4.bzoj4033  https://www.lydsy.com/JudgeOnline/problem.php?id=4033

    题解:https://www.cnblogs.com/L-Memory/p/9768069.html

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 2001
    #define ll long long
    
    using namespace std;
    int n,k,ans,cnt,S,T;
    int head[N],siz[N];
    ll f[N][N],tmp;
    struct edge{
        int u,v,net;
        ll w;
    }e[N<<1];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    inline void add(int u,int v,ll w)
    {
        e[++cnt].v=v;e[cnt].w=w;e[cnt].net=head[u];head[u]=cnt;
    }
    
    ll calc(ll val,int num,int x) 
    {
        val=val*x*(k-x)+val*(num-x)*(n-k-(num-x));
        return val;
    }
    
    void dfs(int u)
    {
        siz[u]=1;
        for(int i=head[u];i;i=e[i].net)
        {
            int v=e[i].v;
            if(siz[v]) continue;
            dfs(v);
            for(int x=siz[u];x>=0;x--) for(int y=siz[v];y>=0;y--)
            {
                tmp=f[u][x]+f[v][y]+calc(e[i].w,siz[v],y);
                f[u][x+y]=max(f[u][x+y],tmp);
            }
            siz[u]+=siz[v];
        }
    }
    
    int main()
    {
        int x,y,z;
        n=read();k=read();
        for(int i=1;i<n;i++)
        {
            x=read();y=read();cin>>z;
            add(x,y,z);add(y,x,z);
        }
        dfs(1);printf("%lld
    ",f[1][k]);
        return 0; 
    }
    Code

    5.bzoj2525  https://www.lydsy.com/JudgeOnline/problem.php?id=2525

    题解:https://www.cnblogs.com/L-Memory/p/9769404.html

    #include<iostream>
    #include<cstdio>
    
    #define N 300007
    
    using namespace std;
    int n,m,h[N],cnt,d[N],sum,sm,mx[N],mn[N];
    struct edge
    {
        int ne,to;
    }e[N<<1];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    void add(int u,int v)
    { 
        e[++cnt].to=v;e[cnt].ne=h[u];h[u]=cnt;
    }
    
    void dfs(int u,int fa,int w)
    {
        mx[u]=-1e9,mn[u]=1e9;
        for(int i=h[u];i;i=e[i].ne)
            if(e[i].to!=fa)
            {
                dfs(e[i].to,u,w);
                mx[u]=max(mx[u],mx[e[i].to]+1);
                mn[u]=min(mn[u],mn[e[i].to]+1);
            }
        if(d[u]&&mn[u]>w) mx[u]=max(mx[u],0);
        if(mx[u]+mn[u]<=w)mx[u]=-1e9;
        if(mx[u]==w) sm++,mx[u]=-1e9,mn[u]=0;
    }
    
    bool ok(int w)
    {
        sm=0;dfs(1,0,w);
        return sm+(mx[1]>=0)<=m;
    }
    
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++)
            d[i]=read(),sum+=d[i];
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            add(x,y),add(y,x);
        }
        if(sum<=m)
        {
            puts("0");return 0;
        }
        int l=0,r=n,ans=n;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(ok(mid)) r=mid-1,ans=mid;
            else l=mid+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    Code
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    《Python数据挖掘入门与实践》高清中文版PDF+英文版+源码下载
    discuz 论坛配置 QQ/163 网易邮箱
    Discuz! X3 去掉内容图片提示下载方法(去除图片提示下载附件)
    HTTPS的建立过程(SSL建立安全会话的过程)
    前端开发之走进Vue.js
    优雅统计代码耗时的4种方法!
    Maven配置多个远程仓库的实现方法
    idea maven 一直报错“Could not transfer artifact ......(系统找不到指定的路径。)”
    IntelliJ IDEA为类和方法自动添加注释
    maven “mvn clean package”和“mvn clean install”有什么不同?
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7470228.html
Copyright © 2011-2022 走看看