【2017/3/2】
【题目:http://ac.jobdu.com/problem.php?pid=1123】
【后附加 滚动数组 改进】
/**********************3stone*********************************
FileName: 九度.1123.采药
Author:3stone
Time:2017/3/2
题意:0-1背包问题【每种物品只有一个】
dp[i][j]:表示前i件物品恰好装入容量为j的背包中所能所得的最大价值
【由于j是恰好,所以需要枚举j属于[0-V]时 dp[n][j],取其最大值;
显然九度测试点没有考察到这一点,最后直接输出dp[n][V]也能AC】
状态分支:每一件物品加入与否
状态转移方程:dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+c[i])
边界:dp[0][j] = 0 【前0件物品放进任何容量的背包,所获价值都只能为0】
注意:若 j<w[i] 即表示背包容量比这个物品还小,无法装入
***********************3stone***********************************/
#include<cstdio>
#include<algorithm>
#define INF 0x7fffffff
using namespace std;
struct E{
int w; //花费
int v;//价值
}list[110];
int dp[110][1010]; //前i件物品恰好装入容量为j的背包中所能所得的最大价值
int main(){
int t, m;
while(scanf("%d%d", &t, &m) != EOF){
for(int i = 1; i <= m; i++){
scanf("%d%d", &list[i].w, &list[i].v);
}
for(int i=0; i<=t; i++) dp[0][i] = 0;//边界
int ans = 0;
for(int i=1; i<=m; i++){//遍历每一个物品
for(int j=t; j>=list[i].w; j--){//每一种容量
dp[i][j] = max(dp[i-1][j],
dp[i-1][j-list[i].w]+list[i].v);
}
for(int j = list[i].w-1; j>=0;j--){
//list[i].w>j表示此物品体积大于背包容量,无法装入,
只能由dp[i-1][j]而来
dp[i][j] = dp[i-1][j];
}
}
printf("%d\n", dp[m][t]);
}
return 0;
}
【使用滚动数组降低空间复杂度】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x7fffffff
using namespace std;
struct E{
int w;
int c;
}list[110];
int dp[110];//使用一维数组保存结果,因为d[i][j]只用到了
//dp[i-1][j] 和dp[i-1][j-list[i].w],可以覆盖保存
int main(){
int V, n;
while(scanf("%d%d", &V, &n) != EOF){
for(int i = 1;i <= n; i++){
scanf("%d%d", &list[i].w, &list[i].c);
}
for(int i=0; i<=V; i++) dp[i] = 0;//边界
for(int i=1; i<=n; i++){//主要变动;必须逆序遍历V,保证要用到的
(int j=V;j>=list[i].w;j--){//dp[j-list[i]]没被本轮修改
dp[j]= max(dp[j], dp[j-list[i].w] + list[i].c);
}
}
int max = 0;//并非恰好装满
for(int i=1;i<=V;i++){
if(max<dp[i])
max = dp[i];
}
printf("%d\n", max);
}
return 0;
}