• 重建道路


    题目链接

    树形dp,以深度为阶段,

    dp[i][j]表示i结点为根的子树中,保留j个结点(必须保留i结点)最多保留多少边

    天真的思路:总边数-最大保留=最小去掉

    然而这样会把不需要的儿子和它的子子孙孙的连边都删了,,,

    但其实只需要删除儿子和当前结点的连边,所以状态会与决策过程中从几个儿子转移过来有关系,需要加一维

    dp[i][j]表示i结点为根的子树中,保留j个结点(必须保留i结点),i与i的父亲相连,最少删多少边

    dp[i][0]=正无穷,dp[i][1]=儿子个数,枚举儿子,考虑是否要加上当前儿子并把删去的边数-1

    统计结果时非根结点需要+1删去与父亲相连的边

    代码

    #include<bits/stdc++.h>
    using namespace std;	
    int n,p,f[200],in[200],out[200],sum[200],nxt[200],minn=200,head[200],dp[200][200];
    void build(int father,int son)
    {
    	f[son]=father;
    	nxt[son]=head[father];
    	head[father]=son;
    }
    void dfs(int u)
    {
    	dp[u][1]=out[u];
    	for(int i=head[u];i;i=nxt[i]) dfs(i);
    	for(int i=head[u];i;i=nxt[i])
    	for(int j=p;j>=1;j--)
    	{
    		for(int k=j;k>=1;k--)
    		dp[u][j]=min(dp[u][j],dp[i][k]+dp[u][j-k]-1);
    	}
    	if(in[u]) minn=min(minn,dp[u][p]+1);
    	else minn=min(minn,dp[u][p]);
    }
    int main()
    {
    	memset(dp,0x3f,sizeof(dp));
    	cin>>n>>p;
    	for(int i=1;i<n;i++)
    	{
    		int u,v;
    		cin>>u>>v;
    		build(u,v);
    		in[v]++;
    		out[u]++;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		if(in[i]==0)
    		{
    			dfs(i);
    			cout<<minn;
    			break;
    		}
    	}
    	return 0;
    }
    

    dp[i][j]表示i结点为根的子树中,保留j个结点(必须保留i结点),i不与i的父亲相连,最少删多少边

    dp[i][1]=i的所有连边数

    转移的时候要-2因为对于每条边儿子和父亲都减了一次

  • 相关阅读:
    wordpress建个人博客
    函数(一)
    字符串格式化
    集合运算
    基本数据类型(二)
    基本数据类型(一)
    分享一个下片神器
    Proxyee
    基本运算符
    条件语句和while循环
  • 原文地址:https://www.cnblogs.com/qwq-/p/13680135.html
Copyright © 2020-2023  润新知