洛谷P2938(2019.8.11)

今天写了洛谷P2938
第一次看这个问题的时候觉得这是一个分组背包,类似于金明的预算方案或者说是软件安装这样的题目
然后呢,把树形DP代码敲上去,发现只有23分QAQ
原因在于,这个数据规模太大了,这样会超时。。。
这个题,要考察的点还是蛮多的
考虑到数据大,而且这个树的深度也就那么2层,用树形DP是没必要的。
所以考虑二维DP
dp[i][j]表示的是选择前i件物品花费j所得到的最大收益
然后内存就爆了
dp[i][j]中的内容是由dp[i-1][j]推出来的
所以我们不需要关心用这个物品前几个物品的收益,只需要上一层的。
所以不妨新建一个数组ans[i],表示当前阶段用i元可以收获的最大收益
所以我们每次在一个主机的循环结束以后,就及时更新花费的最大值ans[i],也就是用使用了当前主机的f[i]来更新
也就是说我们然后每次进入新的主机的循环的时候,我们就需要f数组初始赋值,然后进行dp后更新ans数组
达到一个滚动的效果,就没那么消耗空间
注意循环的时候的边界和倒序(01背包嘛!)
代码:

#include<bits/stdc++.h>
using namespace std;
int f[10000010];
int ans[10000010];
int main(){
	int n;
	int money;
	cin>>n>>money;
	int t=n;
	while(t--){
		int zhuji;
		int num;
		cin>>zhuji>>num;
		for(int j=zhuji;j<=money;j++){
			f[j]=ans[j-zhuji];//每次把上次更新过的数组f进行更新,因为要进行下一次物品购买,所以的话必须更新f数组 
		}

		for(int i=1;i<=num;i++){
			int price,value;
			cin>>price>>value;
			for(int j=money;j>=zhuji+price;j--){//最大投入到这块的费用肯定就是背包的容积,而且至少要买下主机才能获得收益
				f[j]=max(f[j],f[j-price]+value);
			}
		}
		
		for(int j=zhuji;j<=money;j++){
			ans[j]=max(f[j],ans[j]);
		}
	}
	cout<<ans[money];
} 

所以,其实算法必须要做到活学活用,不能简简单单拘泥于一种算法而不去深入思考,也不能简简单单套个模板,觉得万事大吉,而是要去深入发掘题目背后所隐含的内容,然后经过思考和优化后达到算法的优化,然后解决实际问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值