思路
很显然这就是一个01背包经典题目,对于每一个“物品”都可以选择采或者不采。
采的话那就获得了本物品的价值并且花费了采药的时间。
不采的话那就既不获得本物品的价值也不花费时间。
状态转移方程为
F [ i ] [ j ] = m a x { F [ i − 1 ] [ j − w [ i ] ] + v [ i ] , f [ i − 1 ] [ j ] } F[i][j] = max\{F[i-1][j-w[i]]+v[i],f[i-1][j]\} F[i][j]=max{F[i−1][j−w[i]]+v[i],f[i−1][j]}
F(i,j)表示当拥有j个时间时选取前i件物品的最优解
#include <cstdio>
int w[102],v[102];
int f[120][1200];
int n,C;
int max(int x,int y){return x>y?x:y;}
int main()
{
register int i,j;
// freopen("1.in","r",stdin);
scanf("%d%d",&C,&n);
for(i=1;i<=n;i++)scanf("%d%d",&w[i],&v[i]);
for(i=1;i<=n;i++)
{
for(j=1;j<=C;j++)
{
if(j < w[i])f[i][j] =f[i-1][j];//时间不够肯定采不了
else
{
f[i][j] = max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
}
}
}
printf("%d\n",f[n][C]);
return 0;
}
优化
仔细想想,你所申请的数组其实有很大的浪费,其实用一个一维数组也可以ac这一题
F [ j ] = m a x { F [ j − w [ i ] ] + v [ i ] , f [ j ] } F[j] = max\{F[j-w[i]]+v[i],f[j]\} F[j]=max{F[j−w[i]]+v[i],f[j]}
没错只是少了个i,也就是空间由f[m][n]压缩成了f[n],节省了不少空间,但是这样的话就意味着第二重循环不能从0到n,这是为什么呢?
因为如果从小到大循环由于前面的数字被更新过,你后面更新出来的数字是个什么玩意?
#include <cstdio>
int n,m;
int f[1050];
int w[100];
int v[100];
int max(int x,int y){return x>y?x:y;}
int main()
{
register int i,j;
freopen("in","r",stdin);
scanf("%d",&n);
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",w+i,v+i);//嫖来的更方便的方法,仔细想想有点道理
}
for(i=1;i<=m;i++)
{
for(j=n;j>=0;j--)
{
if(j >= w[i])
f[j] = max(f[j-w[i]] + v[i],f[j]);
}
}
printf("%d\n",f[n]);
return 0;
}