码迷,mamicode.com
首页 > 其他好文 > 详细

树形dp

时间:2017-09-03 18:38:52      阅读:125      评论:0      收藏:0      [点我收藏+]

标签:p12   using   return   背包   img   ret   dfs   bre   define   

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\n",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\n",ans);
    return 0;
}
Code

 

树形dp

标签:p12   using   return   背包   img   ret   dfs   bre   define   

原文地址:http://www.cnblogs.com/L-Memory/p/7470228.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!