DP问题入门到精通5(树形dp,记忆化)

本文通过实例解析动态规划(DP)的基本概念,包括树形DP和记忆化搜索。介绍了如何从题目中提炼状态表示和状态转移方程,并提供了两个具体问题——'没有上司的舞会'和'滑雪'的解决方案。通过这两个问题,深入理解DP的应用和解决思路。
摘要由CSDN通过智能技术生成

DP入门到精通系列

学到这,树形dp,和记忆化这些其实都很简单,且是很常见的思路。那么话不多说直接开始dp之旅吧。

没有上司的舞会

不管三七二十一,dp问题是一定要去思考状态表示的,而这个一般都是从题目里面就会给到你

没有职员愿意和上司一起参会(太真实了),用算法语言来说就是你选了这个就不能选那个,也就是说,如果你选了父节点,就不可以选子节点,,所有就有 f[ u , 0 ],f[ u , 1 ]表示你选与不选这第u个结点,其实没有职员愿意和上司一起参会这句话还顺路把状态计算给了出来

因为如果你选了这个结点f[ u , 1 ],那么你就不能选子节点,(假设s是子节点)所以必然是f[ u ][ 1 ]+=f[ s ][ 0 ],如果你没选这个f[ u , 0 ]那么就可以在子节点中抉择选与不选,f[ u ][ 0 ]+=max(f[ j ][ 0 ],f[ j ][ 1 ])。

const int N =6010;
int n;
int f[N][2];
int e[N],ne[N],happy[N],h[N],idx=0;
void add(int a,int b)//邻接表存图
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool has_father[N];
void dfs(int u)
{
    f[u][1]=happy[u];
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        dfs(j);
        f[u][0]+=max(f[j][0],f[j][1]);
        f[u][1]+=f[j][0];
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>happy[i];
    memset(h,-1,sizeof h);
    for(int i=0;i<n-1;i++)
    {
        int a,b;
        cin>>a>>b;
        add(b,a);
        has_father[a]=true;
    }
    int root=1;
    while(has_father[root++]);//找到根节点
    root-=1;
    dfs(root);
    
    cout<<max(f[root][0],f[root][1]);
    return 0;
}

滑雪 

滑雪问题大家应该不陌生,但面对dp问题我们还是先老套路,状态表示,状态计算,我们可以这么表示,f [ i , j ]表示从i j 出发的最大路径是多少,然后 f [ i , j ]他可以往左往右,向上向下去滑,那么f [ i , j ]的值就是朝这四个方向滑的最大值。所以我们也顺便把状态计算写了出来

 

f[ i ][ j ] =max(f[ i ][ j ],(上下左右)+1);

/*
输入格式
第一行包含两个整数 R 和 C。

接下来 R 行,每行包含 C 个整数,表示完整的二维矩阵。

输出格式
输出一个整数,表示可完成的最长滑雪长度。
*/
const int N = 310;
int f[N][N];
int h[N][N];
int n,m;
int dirx[4]={0,1,0,-1};
int diry[4]={1,0,-1,0};
int dp(int x,int y)
{

    if(f[x][y]!=-1)return  f[x][y];
    
    f[x][y]=1;
    for(int i=0;i<4;i++)
    {
        int dx=dirx[i]+x;
        int dy=diry[i]+y;
        
        if(dx>=1&&dx<=n&&dy>=1&&dy<=m&&h[dx][dy]<h[x][y])
        {
            f[x][y]=max(f[x][y],dp(dx,dy)+1);
        }
    }
    
    return f[x][y];
}
int main()
{
    memset(f,-1,sizeof f);
    cin>>n>>m;
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        cin>>h[i][j];
    }
    int res=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        res=max(res,dp(i,j));
    }
    cout<<res;
    return 0;
}

 DP问题入门到精通结束

不知不觉也写了挺多的了,我也从中学到了很多,教学相长确实如此,虽然我也不至于有“教”这个境界吧

 

更多的是想我的思路,学习心得能够帮到别人,所以还是那句话,希望能让看完的你有所收获吧哈哈哈。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值