poj1947(Rebuilding Roads 树中独立出m个点 最少切割的边数 树形背包dp)

题目
在这里插入图片描述题意: 在n个结点n-1条边的树中取一个子树(包含m个点)所需要的最少切割的边数。
思路: dp[x][j]:以x为根的子树中,取m个点 包括x 所需要最少切割的边数。这个留下的m个点显然是联通的。
注意这个dp[x][j]的定义。

#include<cstdio>
#include<iostream>
#include<cstring>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=150+5,INF=0x3f3f3f3f;
struct Edge{int to,nex;}edge[N<<1];int head[N],tot;
inline void add(int from,int to){
    edge[++tot]=(Edge){to,head[from]},head[from]=tot;
    edge[++tot]=(Edge){from,head[to]},head[to]=tot;
}
int in[N],dp[N][N],n,m;
void dfs(int x,int fa){
    dp[x][1]=0;//看21行代码 就知道这一行初始化的道理啦
    for(int i=head[x];i;i=edge[i].nex){
        int y=edge[i].to;
        if(y==fa) continue;
        dfs(y,x);
        for(int j=m;j>=1;--j){
            dp[x][j]=dp[x][j]+1;//y这颗子树一个都不入选
            for(int k=1;k<j;++k){//y这颗子树入选k个
                dp[x][j]=min(dp[x][j],dp[y][k]+dp[x][j-k]);
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<n;++i) scanf("%d%d",&x,&y),add(x,y),++in[y];
    m(dp,INF);
    if(n==1) {printf("0\n");return 0;}
    int root;
    for(int i=1;i<=n;++i) if(!in[i]) {root=i;break;}//叶子节点作为根节点 没有父亲
    dfs(root,root);
    int ans=dp[root][m];
    for(int i=1;i<=n;++i) ans=min(ans,dp[i][m]+1);
    printf("%d\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值