机试算法讲解: 第54题 0-1背包之如何采药

来源:互联网 发布:htpc必备软件 编辑:程序博客网 时间:2024/05/22 08:16
/*背包:种类:0-1背包,完全背包,多重背包。     0-1背包:含义:有一个容量为V的背包和物品,物品与两个属性,体积W和价值V,每种物品只有1个。                  要求用这个背包装下价值尽可能多的物品,求该最大价值,背包可以不被装满。             特点:每个物品至多能选1件,物品数量只有0和1两种情况。 dp[i][j]:表示总体积不超过j的情况下,前i个物品所能达到的最大价值 初始化:dp[0][j]=0(0<=j<=s) 关键:采用逆序循环,保证更新dp[j]时,dp[j-list[i].w]是没有放入物品i时的数据dp[i-1][j-list[i].w]状态未因为本次更新发生改变 for(i = 1 ; i <= n ; i++)  {for( j = s ;j >= list[i].w ; j++){dp[j] = max{dp[j],dp[j-list[i].w]+list[i].v}}  }0-1背包变体:dp[i][j]:前i个物品总体积恰好为v时所能达到的最大价值,只需改动初始化:dp[0][0]=0,其他dp[0][j]均为负无穷或不存在                  完全背包:一个容积为V的背包,同时有n个物品,每个物品均有各自的体积W和价值v,每个物品的数量均为无限个,求试用该背包最多能装的物品价值总和。          改动代码:每个物品可以被无限次选择,那么状态dp[i][j]恰好可以由可能已经放入物品i的状态dp[i][j-list[i].w]转移而来,所以这里将状态的遍历顺序变为  顺序,使在更新状态dp[j]时,dp[j-list[i].w]可能因为放入物品i而发生改变。  for(i = 1 ; i <= n ; i++)  {for(j = list[i].w ; j <= s ; j++){dp[j] = max{dp[j],dp[j-list[i].w]+list[i].v}}  }问题:采药。不同草药,采每一株需要一些时间,每一株有自己价值,如何让采到的价值最大。输入:第一行有两个整数T(1<=T<=1000)和M(1<=M<=100),T代表总共能够用来采药的时间,M代表山洞里的草药数目。     接下来的M行,每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值输出:在规定时间内,可以猜到的草药的最大总价值输入:70(T采药总时间) 3(M,M行,每行是采药时间和价值)71 10069 11 2输出:3思路:0-1背包:每个物品装或者不装(背包中有0个或者1个该物品)。这里总共时间=容积,物品体积=采摘每个草药时间。     用dp[i][j]:表示总体积不超过j的情况下,前i个物品所能达到的最大价值。初始时:dp[0][j](0<=j<=V)=0。每个状态有2个状态转移来源。 若物品i放入背包,体积为w,价值为v,则dp[i][j] = dp[i-1][j-w]+v。即在总体积不超过j-w时,前i-1件物品可组成的最大价值的基础上再 加上i物品的价值v。若物品不加入背包,则dp[i][j]=dp[i-1][j]。状态转移方程:dp[i][j] = max{dp[i-1][j-w]+v,dp[i-1][j]};注意:j-w的值是否为负值,若为负,则转移来源能被转移。目标状态:dp[n][s]关键:1 0-1背包状态转移方程:dp[i][j] = max{dp[i-1][j-w]+v,dp[i-1][j]};,用 j >= list[i].w作区分,优化后的转移方程:dp[j] = max{dp[j-w]+v,dp[j]}2 目标状态是:dp[n][s],s是总容量,n是物品总数3 必须声明一个结构list:v,w表示价值和体积4 倒序遍历j,保证确定dp[j]的值时,dp[j-list[i].w]的值尚未被修改5 0-1背包复杂度=状态数量*状态转移复杂度=(物品数量n*背包总容积s)*O(1)=O(n*s),优化过后空间复杂度为O(s)*/#include <stdio.h>#include <stdlib.h>#include <string.h>//定义背包typedef struct List{int w;//体积int v;//价值}List;int max(int a,int b){return a > b ? a:b;}int main(int argc,char* argv[]){int s;//总容积int n;//n行int i,j;while(EOF!=scanf("%d %d",&s,&n)){List list[101];//int dp[101][1001];int dp[1001];//优化for(i = 1 ; i <= n ; i++){scanf("%d %d",&list[i].w,&list[i].v);}//初始化状态量for(i = 0 ; i <= s ; i++){//dp[0][i] = 0;dp[i] = 0;}//对于时间足够的情况,状态来源是:dp[i][j]为两者之中的最大值for(i = 1 ; i <= n ; i++){for(j = s; j >= list[i].w ; j--){//dp[i][j] = max(dp[i-1][j],dp[i-1][j-list[i].w] + list[i].v);//优化:必须倒序更新每个dp[j]的值,j小于list[i].w的各dp[j]不做更新,保持原值,即等价与dp[i][j] = dp[i-1][j]dp[j] = max(dp[j],dp[j-list[i].w] + list[i].v);}/*for(j = list[i].w-1; j >= 0 ; j--){dp[i][j] = dp[i-1][j];}*/}//printf("%d\n",dp[n][s]);printf("%d\n",dp[s]);}system("pause");getchar();return 0;}

0 0