poj 1947 树形dp 背包

题意:求得到p个点最少删除多少条边。p个点事连通的。

题解:dp【u】【j】 以u为根得到j个点需要的最大价值。

对于一个子节点 v 两种选择,要和不要。

 不要的话,就删除u与v相连的边。 即dp【u】【j】+=1;

要的话,即进行背包  dp【u】【j】=min(dp【u】【j】,dp【u】【j-k】+ dp【v】【k】);

对于节点 u 我们没有考虑它的父节点,在最后求解时,dp【i】【p】加上1 (根节点除外),找个最小的即为结果。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
const int N=152;
const int inf=0x3f3f3f3f;
vector<int>V[N];
int dp[N][N],in[N];
int p;
void dfs(int u)
{
    for(int i=0;i<=p;i++)
      dp[u][i]=inf;
    dp[u][1]=0;
    for(int i=0;i<(int)V[u].size();i++)
    {
        int v=V[u][i];
        dfs(v);
        for(int j=p;j>=0;j--)
        {
            dp[u][j]+=1;//减去子树 v
            for(int k=1;k<j;k++)
            {
                dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]);//不减去子树 v.
            }

        }
    }
}
int main()
{
    //freopen("Input.txt","r",stdin);
    int n,i;
    while(~scanf("%d%d",&n,&p))
    {
        for(i=0;i<=n;i++) V[i].clear();
        memset(in,0,sizeof(in));
        memset(dp,0,sizeof(dp));
        for(i=1;i<n;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            V[a].push_back(b);
            in[b]=1;//入度标记
        }
        for(i=1;i<=n;i++)
          if(in[i]==0)
            break;//找根节点
        dfs(i);
        int ans=dp[i][p];//除根节点外的点要作为根节点要减去与父节点相连的边,所以加1,
        for(int i=1;i<=n;i++)
          if(ans>dp[i][p]+1)
            ans=dp[i][p]+1;
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值