采药(01背包二维数组详细解释版||一维数组略解吧)

vjudge提交链接

题目:采药

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

Input
——输入第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 10),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

Output
——输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

Sample Input
70 3
71 100
69 1
1 2

Sample Output
3

解题思路:

01背包二维数组过程详解看完一定不后悔,只要会构建表格,思路就会超级清晰。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int T=1010;
const int M=11;
int dp[M][T];//构建一个M*T的表格,m行草药,T列的容量。
int p[M],w[M];
//dp[i][j]表示前i件草药恰好放入一个容量为j的背包可以获得的最大价值
int main()
{
	int t,m,i,j;
	while(~scanf("%d %d",&t,&m))
	{
		memset(dp,0,sizeof(dp));
		for(i=1;i<=m;i++)
		{
			//其实scanf("%d %d",&p,&w);就行
			scanf("%d %d",&p[i],&w[i]);
			for(j=1;j<=t;j++)
			{
				if(j<p[i])//不能采 
					dp[i][j]=dp[i-1][j]; 
				else
					dp[i][j]=max(dp[i-1][j],dp[i-1][j-p[i]]+w[i]);		
			}	
		}
		printf("%d\n",dp[m][t]);
	}
	return 0;
}

优化空间复杂度

——将for(j=1;j<=t;j++)改为将for(j=t;j>0;j–)就可以改为一维数组了

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[1010];//dp[i]表示在时间i内能获得的最大价值  
int p[20],w[20];
int main()
{
	int t,m,i,j;
	while(~scanf("%d %d",&t,&m))
	{
		memset(dp,0,sizeof(dp));
		for(i=1;i<=m;i++)
		{
			//其实scanf("%d %d",&p,&w);就行
			scanf("%d %d",&p[i],&w[i]);
			for(j=t;j>=p[i];j--)
				dp[j]=max(dp[j],dp[j-p[i]]+w[i]);
		} 
		printf("%d\n",dp[t]);
	}
	return 0;
}

可以不看

解题思路:

状态转移方程:dp[j]=max(dp[j],dp[j-p[i]]+w[i]);
dp[j]表示在j时间内能获得的最大价值

最初:拥有时间为t,草药价值为0
使手中的草药价值最大,利用dp思想
dp思想:在当前情况下,判断该行为可行还是不可行,可行就把数据保留,不可行就不保留数据。
所以当面对一颗草药时,首先要做的就是判断采摘它划不划算,根据状态转移方程去判断

给出一组数据:
t=5,下面给出2种草药的采摘时间和价值
3 5
4 6

3 5:只要手中握有的时间j>=3,便可获得该价值,因此dp[3]=dp[4]=dp[5]=5;
4 6:只要手中握有的时间4<=j<7,那么根据状态转移方程,dp[4]=dp[5]=6
明显这枚草药价值更大,当摘完这枚草药后,所剩时间j-p[i]=0,不足以采摘第一颗草药了
假如拥有的时间为t=7,那当摘第二颗草药后,所剩时间j-p[i]=3,仍然可以采摘第一颗草药,从而dp[7]=6+5=11

回顾01背包核心

for(i=0;i<m;i++)
{
	for(j=t;j>=p[i];j--)
		dp[j]=max(dp[j],dp[j-p[i]]+w[i]);
} 

当面对第i株草药并且可以采摘它时,当前拥有时间为j。
现在要考虑就是采摘它值不值得,能不能使当前dp[j]变的更大
一种是不采:dp[j] 当前拥有的价值不变
一种是采摘:dp[j-p[i]]+w[i] 该草药的价值+所剩时间可获得价值
如果采摘后dp[j]变小了,说明在当前的情况下采摘该株草药是不划算的
如果采摘后dp[j]变大了,说明在当前的情况下采摘是划算的

注意:dp是数组,很多情况下保留最优。

猜你喜欢

转载自blog.csdn.net/Helinshan/article/details/114743405
今日推荐