POJ1947 Rebuilding Roads 树形DP

本文介绍了一种使用树形动态规划(DP)的方法来解决一个特定的问题:如何通过最少次数的切割使得树上剩余指定数量的节点。通过定义状态转移方程,实现了高效的求解算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给你一棵树,然后问你最少切多少刀可以剩下p个节点
n,p<=200吧,大概。
又是经典模型,设f[i,j]表示以i为根的子树中,最少去掉多少条边能剩下j个节点。
那么就是分类讨论咯。。
设v是x的子树,x是当前节点
有:
1.不切v子树,那么就有f[i,j]=min(f[i,j],f[i,k]+f[v,j-k]);(0<=k<=j)
2.切,那么直接f[i,j]++就可以了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define inf 2147483647/3
using namespace std;
int i,n,m,p=0;
const int N=1e5+6;
int a[N],go[N],next[N],head[N],f[3000][3000],tot;
inline void add(int x,int y)
{
    go[++tot]=y;
    next[tot]=head[x];
    head[x]=tot;
}
inline void dfs(int x,int fa)
{
    int i,v;
    i=head[x];
    fo(i,0,p)f[x][i]=inf;
    f[x][1]=0;
    i=head[x];
    while (i)
    {
        v=go[i];
        if (v!=fa)
        {
            dfs(v,x);
            for(int j=p;j>=1;j--)
            {
                int tmp=f[x][j]+1;
                fo(k,0,j)
                tmp=min(tmp,f[x][k]+f[v][j-k]);
                f[x][j]=tmp;
            }
        }
        i=next[i];
    }
}
int main()
{
    scanf("%d%d",&n,&p);
    fo(i,1,n-1)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    int ans=f[1][p];
    fo(i,1,n)
    ans=min(ans,f[i][p]+1);
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值