蓝桥杯备战——Day 2 采药1

介绍*

本系列是记录我备战蓝桥杯刷题记录
第一天未记录,从这天开始更新,仍然算第二天

题目

题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式
第一行有 2个整数 T(1 <= T <= 10001)和 M(1<=M<=100),用一个空格隔开,T 代表总共能够用来采药的时间,MM 代表山洞里的草药的数目。

接下来的 MM 行每行包括两个在 1 到 100之间(包括 1 和 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式
输出在规定的时间内可以采到的草药的最大总价值。

输入输出样例
输入 #1复制
70 3
71 100
69 1
1 2
输出 #1复制
3

解题思路

此题是背包dp
背包dp的思路是,将物品种类和背包容量列表
其中物品种类为列,背包容量为行
示例: 1 2 3 (容量)
物品1
物品2 m
物品3
一行一行分析,第一行就是当只能拿物体1时候,然后依次看背包容量为1,2,3的时候能装多少
第二行就是当能拿物体1,2时候,然后。。。。。。。
具体思路:考虑列表中m,此时对于物品2,有两种可能,我这个容量为2的背包(空的)能拿下物品2吗
1.能拿下:
那我要不要拿呢,那么就比较一下 拿了->(该物体价值+剩余背包最多能拿多少) 没拿->(之前的同样容量的最大价值)
同时我们也看到,剩余背包最多能拿多少,其实就是上一行的其中数据
而之前同样容量的能拿多少,也是上一行的数据,因此我们只需要两行就可以,交替使用
2.拿不下:
拿不下怎么办,那就直接继承之前同容量的最大价值

	这样直到把所有表格填满,然后表格右下角那个就是答案
	
	时间复杂度为O(m*n) m是容量,n是物体个数

代码

#include
#include
using namespace std;
int T,M;
int a[102][2];//草药的时间和价值 
int dp[2][1002]={0};
int ans_i;
int main(){
	cin>>T;cin>>M;//T为总时间,M为草药数目 
	for(int i=0;i<M;i++){
		cin>>a[i][0]>>a[i][1];//a[0]为时间,a[1]为价值。 
	} 
	for(int i=0;i<M;i++){//遍历M种草药,我们从0开始,便于后面只用两行数组 
		for(int j=1;j<=T;j++){//遍历时间 
			if(j>=a[i][0]){//判断是否能拿,此处是能拿 
				dp[i%2][j]=max(dp[(i+1)%2][j],a[i][1]+dp[(i+1)%2][j-a[i][0]]);
			}
			else{//如果不能拿 
				dp[i%2][j]=dp[(i+1)%2][j];
			}
		}
		ans_i=i;
	}
	cout<<dp[ans_i%2][T];
	return 0;
}

你可能感兴趣的:(蓝桥杯备战,算法)