01背包问题
假设你有一个背包,最多能承重M千克,这里有N个物品,其重量分别为w1、w2、……、wN,其价值分别为v1、v2、……、vN,在背包所能承受的重量下,尽可能得使背包里的价值最大。(注意,该物品只能放或者不放,不能只放该物品的0.8这样子,非0即1,故称为01背包问题)
二维数组
f[i][j]表示装到第i个物体,背包内不超过j千克时,最大的价值数
#include <iostream>
using namespace std;
const int N=1010;
int v[N],w[N],f[N][N];
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&w[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
f[i][j]=f[i-1][j];
if(j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
printf("%d",f[n][m]);
return 0;
}
一维数组
是二维数组的一种优化,可以看到,遍历到当前物体的结果只与前一个物体的结果有关,并不需要记录每一个物体的结果。
#include <iostream>
using namespace std;
const int N=1010;
int v[N],w[N],f[N];
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&w[i]);
for(int i=1;i<=n;i++)
for(int j=m;j>=v[i];j--)
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
printf("%d",f[m]);
return 0;
}
牛客【2021】阿里巴巴编程题(4星)
7.牛牛们吃糖果
有n个牛牛一起去朋友家吃糖果,第i个牛牛一定要吃ai块糖果.而朋友家一共只有m块糖果,可能不会满足所有的牛牛都吃上糖果。同时牛牛们有k个约定,每一个约定为一个牛牛的编号对(i,j),表示第i个和第j个牛牛是好朋友,他俩要么一起都吃到糖果,要么一起都不吃。
保证每个牛牛最多只出现在一个编号对中。
您可以安排让一些牛牛吃糖果,一些牛牛不吃。
要求使能吃上糖果的牛牛数量最多(吃掉的糖果总量要小于等于m),并要满足不违反牛牛们的k个约定。
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 256M,其他语言512M
思路
把一对牛牛合成一个,对应的value变为2,就转换成了01背包问题
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n,m;
cin>>n>>m;
vector<vector<int>> a(n,vector<int>(2,1));
for(int i=0;i<n;i++){
cin>>a[i][0];
}
int k;
cin>>k;
for(int i=0;i<k;i++){
int u,v;
cin>>u>>v;
a[u-1][0]+=a[v-1][0];
a[u-1][1]=2;
a[v-1][1]=0;
a[v-1][0]=0;
}
// sort(a.begin(),a.end(),[](vector<int> i,vector<int> j){
// if(i[0]==j[0]) return i[1]>j[1];
// else return i[0]<j[0];
// });
vector<int> dp(m+1);
for(int i=0;i<n;i++){
for(int j=m;j>=a[i][0];j--){
dp[j]=max(dp[j],dp[j-a[i][0]]+a[i][1]);
}
}
cout<<dp[m];
return 0;
}
// 64 位输出请用 printf("%lld")