树形DP 洛谷P1490 奶思

本文探讨了两种记忆化搜索的实现方式,一种基于递归DFS,另一种采用更高效的时间复杂度。通过对比两个代码实例,讲解了如何利用记忆化搜索优化问题求解过程,特别是在树形结构的数据上。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

- -、 在这里

第一个代码 很巧妙
数据是 dfs 过后的数据 因为本来dfs就是一种递归
那么就可以去递归的重新读数据
重新 递归 dfs 但是时间效率不是很高
记忆化搜索

在这里插入图片描述

//MADE BY Y_is_sunshine;
//#include <bits/stdc++.h>
//#include <memory.h>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <cstdio>
#include <vector>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <math.h>

#define INF 0x3f3f3f3f
#define MAXN 1005

const int mod = 1e9 + 7;

using namespace std;

struct node {
	int to;
	int next;
}edge[MAXN << 1];

int N, M;
int cnt_1 = 0;
int cost[MAXN * 10];
int price[MAXN * 10];
int dp[MAXN][MAXN];

void read(int x) {
	cin >> cost[x] >> price[x];
	cost[x] *= 2;
	if (!price[x])
		read(x << 1), read(x << 1 | 1);
}

int dfs(int u, int time) {
	if (dp[u][time] || !time)
		return dp[u][time];
	if (price[u])
		return dp[u][time] = min(price[u], (time - cost[u]) / 5);
	for (int k = 0; k <= time - cost[u]; k++)
		dp[u][time] = max(dp[u][time], dfs(u << 1, k) + dfs(u << 1 | 1, time - cost[u] - k)); // 二分
	return dp[u][time];
}

int main()
{
	freopen("data.txt", "r", stdin);

	cin >> N;
	
	read(1);
	cout << dfs(1, N - 1) << endl;

	freopen("CON", "r", stdin);
	system("pause");
	return 0;
}

另附 第二个时间效率更高的代码
在这里插入图片描述

巨佬的 代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1001
using namespace std;
int n,cnt,tot;
int f[maxn][maxn];
void dfs()
{
    int root=++cnt,limit,time;
    scanf("%d%d",&limit,&tot);
    limit<<=1;
    if(tot)//子节点 
    {
        for(int time=limit;time<=n;time++)
          f[root][time]=min((time-limit)/5,tot);//判断取多少 
    }
    else
    {
        int left=cnt+1,right;dfs();
        right=cnt+1;dfs();
        for(int time=limit;time<=n;time++)
          for(int lctime=0;lctime<=time-limit;lctime++)//分配给左树的时间 
          {
              f[root][time]=max(f[root][time],f[left][lctime]+f[right][time-limit-lctime]);//左右子树的和 
          }
    }
}
int main()
{
    scanf("%d",&n);n--;
    dfs();
    printf("%d\n",f[1][n]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值