题目描述:
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
输入格式
第一行有 2个整数 T(1≤T≤1000)和 M1≤M≤100),用一个空格隔开,T 代表总共能够用来采药的时间,M 代表山洞里的草药的数目。
接下来的 M 行每行包括两个在 1到 100 之间(包括 1 和 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式
输出在规定的时间内可以采到的草药的最大总价值。
输入输出样例
输入 #1
70 3 71 100 69 1 1 2
输出 #1
3
说明/提示
【数据范围】
- 对于 30%30% 的数据,M≤10;
- 对于全部的数据,M≤100。
题目来源:
思路及部分代码:
1. 分析
我在最初想直接暴力解决这类问题,当然超时了。便对动态规划进行了初步的了解。
在本题中, 先将一个药品的所需时间保存下来,
假设: 能采药草数:mi
能采药草的时间: ti
dp [ mi ] [ ti ] = max (新药草价值 + dp [ mi - 1] [ 采新药草剩余时间 ] , dp [ mi - 1][ ti ] );
2. 求最大值函数
int max(int a, int b){
return (a>b)?a:b;
}
3. 动态规划
int dp_max(int t, int m){
dp[0][0] = 0;
for(int mi = 0; mi < m; mi++){ //药品数
for(int ti = 1; ti <= t ; ti++){ //mi个药品,不同时间能采的最大值
if(mi == 0){
if(ti >= drug_all[mi][0]){
dp[mi][ti] = max(drug_all[mi][1], dp[mi][ti - 1]); //将药品为1时间所能保存的药品最大价格
}
}
else{//其余情况
if(ti >= drug_all[mi][0]){ //能采最新药草
int ti_i = ti - drug_all[mi][0]; //采新药的最新时间
// 新药价值 剩余时间的最大价值 不买最大新药价值
dp[mi][ti] = max(drug_all[mi][1] + dp[mi-1][ti_i], dp[mi - 1][ti]);
//printf("%d ", dp[mi][ti]);
}
else{
dp[mi][ti] = dp[mi - 1][ti];
}
}
//printf("%4d ", dp[mi][ti]);
}
//printf("\r\n");
}
return dp[m-1][t];
}
总代码:
#include <stdio.h>
int drug_all[110][2]; //保存药的数据
int dp[1010][1010]; //动态规划数组
int max(int a, int b){
return (a>b)?a:b;
}
int dp_max(int t, int m){
dp[0][0] = 0;
for(int mi = 0; mi < m; mi++){ //药品数
for(int ti = 1; ti <= t ; ti++){ //mi个药品,不同时间能采的最大值
if(mi == 0){
if(ti >= drug_all[mi][0]){
dp[mi][ti] = max(drug_all[mi][1], dp[mi][ti - 1]); //将药品为1时间所能保存的药品最大价格
}
}
else{//其余情况
if(ti >= drug_all[mi][0]){ //能采最新药草
int ti_i = ti - drug_all[mi][0]; //采新药的最新时间
// 新药价值 剩余时间的最大价值 不买最大新药价值
dp[mi][ti] = max(drug_all[mi][1] + dp[mi-1][ti_i], dp[mi - 1][ti]);
//printf("%d ", dp[mi][ti]);
}
else{
dp[mi][ti] = dp[mi - 1][ti];
}
}
//printf("%4d ", dp[mi][ti]);
}
//printf("\r\n");
}
return dp[m-1][t];
}
int main(){
int T,M;
scanf("%d %d",&T, &M);
//接收数据
for(int i = 0; i < M; i++){
scanf("%d %d",&drug_all[i][0], &drug_all[i][1]);
}
printf("%d\r\n", dp_max(T,M));
return 0;
}
总结:
这段代码实现了一个动态规划算法,用于解决背包问题的变种。它通过填充一个二维数组 dp
来记录在不同的时间和不同的药品数量下的最大药品价格总和。但对动态规划了解还较为模糊,还需练习。
不足之处:
- 注释: 虽然代码中有一些注释,但是有些地方的注释并不够清晰,建议增加更多的注释来解释代码的逻辑和关键步骤,使得代码更易读。
- 函数封装: 目前
dp_max
函数和main
函数耦合度较高,建议将动态规划逻辑封装成一个独立的函数,以提高代码的可读性和可维护性。 - 错误处理: 目前的代码没有对输入进行错误处理,比如输入的时间或药品数量可能为负数,这种情况下代码会出现问题。建议添加输入验证,对不合理的输入进行处理和提示。
改进建议:
- 函数封装: 将动态规划逻辑封装成一个独立的函数,并将其与
main
函数分离,以提高代码的模块化和可维护性。 - 错误处理: 在
main
函数中添加输入验证,对不合理的输入进行处理和提示,以提高代码的健壮性。