原题:https://ac.nowcoder.com/acm/contest/24213/1018
解法一:朴素递归,从后往前,从抽象到边界,记忆化搜索,反推(递归)
解法二:动态规划_01背包,从前往后,从边界到抽象,正推(递推)
两种解法是完全相反的过程
解法一(递归):
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <time.h>
#include <iomanip>
#include <cctype>
#include <string>
using namespace std;
typedef long long ll;
const ll Mod = 1e9 + 7;//https://ac.nowcoder.com/acm/contest/24213/1018
int val[110];//价值
int tim[1010];//时间
int rec[110][1010];//记忆化,记录f(i,j)
//从后往前递归,记录最优子结构避免重复计算(记忆化),,,倒过来就是动规
//f(i,j)采前i个草药,剩余j时间,此时能得到的最大价值
//f(i,j)=max(f(i-1,j),f(i-1,j-tim[i])+val[i]) *max(不采第i株,采第i株)
//f(0,j)=0 *边界
int f(int i,int j){
if(i==0) return 0;
if(rec[i][j]>0) return rec[i][j];//f[i][j]算过了就不用算了
if(tim[i]>j)
rec[i][j]=f(i-1,j);
else
rec[i][j]=max(f(i-1,j),f(i-1,j-tim[i])+val[i]);
return rec[i][j];
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int t,n;cin>>t>>n;
for(int i=1;i<=n;i++)
cin>>tim[i]>>val[i];
cout<<f(n,t)<<endl;
return 0;
}
解法二(dp)
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <time.h>
#include <iomanip>
#include <cctype>
#include <string>
using namespace std;
typedef long long ll;
const ll Mod = 1e9 + 7;//https://ac.nowcoder.com/acm/contest/24213/1018
int val[110];//价值
int tim[1010];//时间
int dp[110][1010];
//从前往后正推,,,,倒过来就是递归
//dp[i][j] 采前i个草药,剩余j时间,此时能得到的最大价值
//状态转移方程 dp[i][j]=max(dp[i-1][j],dp[i-1][j-tim[i]]+val[i]) *max(不采第i株,采第i株)
//dp[0][]=0 *边界
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int t,n;cin>>t>>n;
for(int i=1;i<=n;i++)
cin>>tim[i]>>val[i];
for(int i=1;i<=n;i++){
for(int j=t;j>=0;j--){
if(tim[i]>j) dp[i][j]=dp[i-1][j];
else dp[i][j]=max(dp[i-1][j],dp[i-1][j-tim[i]]+val[i]);
}
}
cout<<dp[n][t]<<endl;
return 0;
}