1 条题解

  • 0
    @ 2025-4-11 16:59:42

    设f[i][j]表示以i为根的子树保留j个节点所去掉的最少边数。初始化f[u][1]=c[u]。c[u]是这个节点的度。转移方程f[u][j]=min(f[u][j],f[u][k]+f[v][j−k]−2)。为什么要减2?这是因为我们在初始化的时候已经把连接父节点和子节点的这条边去掉了。这时候再把他们连起来,为防止重复计算,我们分别把u−>v和v−>u的边去掉(代码中是双向连边)。

    
    #include<bits/stdc++.h>
    using namespace std;
    int c[155],n,p,f[155][205],ans=0x3f3f3f3f;
    struct node
    {
        int next,to;
    }edge[50005];
    int head[50005],cnt;
    inline void add(int from,int to)
    {
        edge[++cnt].next=head[from];
        edge[cnt].to=to;
        head[from]=cnt;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void dfs(int now,int fa)
    {
        f[now][1]=c[now];
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (to!=fa) 
            {
                dfs(to,now);
                for (int j=p;j>=1;j--)
                    for (int k=1;k<j;k++)
                        f[now][j]=min(f[now][j],f[now][k]+f[to][j-k]-2);
            }
        }
    }
    int main()
    {
        memset(f,0x3f,sizeof(f)); 
        n=read(),p=read();
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read();
            c[x]++;c[y]++;
            add(x,y);add(y,x); 
        }
        dfs(1,0);
        for (int i=1;i<=n;i++) ans=min(ans,f[i][p]);
        printf("%d",ans);
        return 0;
    } 
    
    
    • 1

    信息

    ID
    948
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者