今天写了洛谷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];
}
所以,其实算法必须要做到活学活用,不能简简单单拘泥于一种算法而不去深入思考,也不能简简单单套个模板,觉得万事大吉,而是要去深入发掘题目背后所隐含的内容,然后经过思考和优化后达到算法的优化,然后解决实际问题。