01背包问题解释详见博客:
https://blog.csdn.net/mu399/article/details/7722810
此博客主要介绍如何减低空间复杂度,对应题目hihocode #1038
1.先附上最普通没有任何优化的写法
#include <cstdio>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll val[600];
ll wei[600];
ll ans[600][100010];
int main()
{
ll n,m;
cin>>n>>m;
for(int i=0;i<=m;i++)
ans[0][i]=0;
for(int i=1;i<=n;i++)
{
cin>>wei[i]>>val[i];
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
if(j>=wei[i])
ans[i][j]=max(ans[i-1][j],ans[i-1][j-wei[i]]+val[i]);
else
ans[i][j]=ans[i-1][j];
}
}
cout<<ans[n][m]<<endl;
}
2.状态压缩写法,状态转移方程为ans[i][j]=max(ans[i-1][j],ans[i-1][j-wei[i]]+val[i]),观察这个式子发现每次我们只关心状态i与装态i-1的情况所以空间复杂度可以压缩为2*M;
#include <cstdio>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll val[600];
ll wei[600];
ll ans[2][100010];
int main()
{
ll n,m;
cin>>n>>m;
for(int i=0;i<=m;i++)
ans[0][i]=0;
for(int i=1;i<=n;i++)
{
cin>>wei[i]>>val[i];
}
int t=0;
for(int i=1;i<=n;i++)
{
t=(t+1)%2;
for(int j=0;j<=m;j++)
{
if(j>=wei[i])
ans[t][j]=max(ans[(t+1)%2][j],ans[(t+1)%2][j-wei[i]]+val[i]);
else
ans[t][j]=ans[(t+1)%2][j];
}
}
cout<<ans[t][m]<<endl;
}
3.更低的写法,倒过来从j=m执行ans[i][j]=max(ans[i-1][j],ans[i-1][j-wei[i]]+val[i]),当ans[i][j]已经计算过了,就可以确定从ans[i-1][j]已经无用了,那么可以用ans[i-1[j]的位置存储ans[i][j],所以如果倒过来执行就只需1*m的空间
#include <cstdio>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll val[600];
ll wei[600];
ll ans[100010];
int main()
{
ll n,m;
cin>>n>>m;
for(int i=0;i<=m;i++)
ans[i]=0;
for(int i=1;i<=n;i++)
{
cin>>wei[i]>>val[i];
}
for(int i=1;i<=n;i++)
{
for(int j=m;j>=0;j--)
{
if(j>=wei[i])
ans[j]=max(ans[j],ans[j-wei[i]]+val[i]);
else
ans[j]=ans[j];
}
}
cout<<ans[m]<<endl;
}