备战蓝桥杯---树形DP基础2

话不多说,直接看题:

这里与前面的树形DP不同,在这里,对于一个节点,它被覆盖的情况有3种,1.被父亲节点覆盖2.自己选3.其中的一个儿子选了。

因此,我们令dpi0表示一定选i,dpi1为不选i,i被一定被他的儿子覆盖,dpi2表示不选i,i一定被他的父亲覆盖。

因此,我们可以得到状态转移方程:

dpi0=1+

对于dpi1,即它可以被它的儿子覆盖(不一定全部),我们发现对于儿子节点,他们除覆盖父亲的节点外是选dpu0与dpu1的min,而为了覆盖父亲必须有一个dpu0,因此,我们分类讨论:

如果取min时取到了dpu0,那么就和dpi2操作一样,否则,我们挑abs(dpu0-dpu1)min的加上差值即可。

我们用伪代码:

if(i无叶子) dpi1=inf else +inc;

同时,我们注意这是一个无向树,我们要存两倍的边,同时为了遍历我们要添加fa来保证按照树进行DFS。

下面是AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n,a,b,head[10010],cnt,dp[10010][3];
struct node{
    int dian,next;
}edge[20010];
void merge(int x,int y){
    edge[++cnt].dian=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
void dfs(int root,int fa){
    dp[root][0]=1;
    dp[root][2]=0;
    dp[root][1]=0;
    int ccc=1000000;
    for(int i=head[root];i!=-1;i=edge[i].next){
        int hp=edge[i].dian;
        if(hp==fa) continue;
        dfs(edge[i].dian,root);
        dp[root][0]+=min(dp[hp][0],min(dp[hp][1],dp[hp][2]));
        dp[root][2]+=min(dp[hp][0],dp[hp][1]);
        dp[root][1]+=min(dp[hp][0],dp[hp][1]);
    	ccc=min(ccc,dp[hp][0]-dp[hp][1]);
    }
		if(ccc<0) ccc=0;
		dp[root][1]+=ccc;
}
int main(){
    memset(head,-1,sizeof(head));
    cin>>n;
    int root=n*(n+1)/2;
    for(int i=1;i<=n-1;i++){
        cin>>a>>b;
        merge(b,a);
        merge(a,b);
    }
    dfs(1,-1);
    cout<<min(dp[1][0],dp[1][1]);
} 

接题:

我们令dpij表示以i为根节点的子树保留j个点的最大数量。

易得状态转移方程:

dpij=max(dpij,dpv1k+w+dpv2j-k-1).

同时我们注意把边上的权值下放给点即可。

下面是AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n,q,x,y,head[200],v[200],cnt,z,dp[110][110],pos[110][110];
struct node{
    int dian,next,quan;
}edge[210];
void merge(int x,int y,int z){
    edge[++cnt].dian=y;
    edge[cnt].quan=z;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
void dfsquan(int root,int fa){
    for(int i=head[root];i!=-1;i=edge[i].next){
        if(edge[i].dian==fa) continue;
        v[edge[i].dian]=edge[i].quan;
        dfsquan(edge[i].dian,root);
    }
    return;
}
void dfsdp(int root,int fa,int q){
    if(pos[root][q]==1) return;
    if(q==0){
        dp[root][q]=0;
        pos[root][q]=1;
        return;
    }
    int f=0;
    int vk=0;
    int tr[3];
    for(int i=head[root];i!=-1;i=edge[i].next){
        if(edge[i].dian==fa) continue;
        tr[++vk]=edge[i].dian;
        f=1;
        for(int j=0;j<=q;j++){
            dfsdp(edge[i].dian,root,j);
        }
    }
    
    if(!f){
        if(q==1) dp[root][q]=v[root];
        else dp[root][q]=-10000000;
        pos[root][q]=1;
        return; 
    }
        for(int j=0;j<=q-1;j++){
           dp[root][q]=max(dp[root][q],v[root]+dp[tr[1]][j]+dp[tr[2]][q-1-j]);
        }
    pos[root][q]=1;
    return;
}
int main(){
    cin>>n>>q;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n-1;i++){
        cin>>x>>y>>z;
        merge(x,y,z);
        merge(y,x,z);
    }
    dfsquan(1,-1);
    dfsdp(1,-1,q+1);
    cout<<dp[1][q+1];
}
相关推荐
不爱学英文的码字机器17 分钟前
推荐算法梳理,六种主流模型与九步训练流程
算法·机器学习·推荐算法
白狐_7981 小时前
408数据结构第5章:树与二叉树②——遍历、线索树、森林与哈夫曼
数据结构·算法·深度优先
zh路西法1 小时前
【3D SLAM源码解读系列】(二)Small_gicp——5 个积木搭出最优点云配准
c++·pcl·icp·fastgicp·smallgicp·gicp
fpcc3 小时前
ubuntu26环境下的开发环境安装处理
c++·并行编程
致Great4 小时前
科研人的 AI,不该只回答问题:我用字节TraeWork 跑了一遍真实研究任务
算法
纵有疾風起4 小时前
线性表的定义与基本操作 — 从逻辑结构到 ADT 接口
数据结构·算法·408·线性表·adt
charlie1145141915 小时前
Cinux · 第一次跳进 Ring 3:用户态与特权隔离
开发语言·c++·操作系统·开源项目
别动我齐刘海5 小时前
机器学习基础2——C++、OpenCV、点云、Open3D
c++·人工智能·opencv·机器学习·计算机视觉·机器人·ros2
测试_AI_一辰5 小时前
AI Agent 评测最隐蔽的坑-记忆
人工智能·算法·ai·自动化·ai编程
躺不平的理查德5 小时前
Windows C++ 第三方库使用流程备忘录--OpenCV
开发语言·c++