参考文献
1: https://www.acwing.com/solution/content/7438/
2: https://www.acwing.com/blog/content/458/
3. https://www.acwing.com/solution/content/12736/
f[i][j][k]状态表示:前i个物品中选择,其氧气的量至少为j 氮气的量至少为k的选法中重量最小的情况。
状态计算:
不选择a[i],则:f[i - 1][j][k];
选择a[i],则:f[i - 1][ max(0,j - w1[i]) ][ max(0,k - w2[i]) ];
此处与之前的01背包问题不同。 由于前面求的都是不超过体积j的情况,而这题求得为至少体积j的问题
略有不同。
之前的表示中j >= w1 , k >= w2. 才能根据j - w1,j - w2去跟新。
此题不同,由于需要至少j和k, 所以当 j <= w1或者k <= w2的时候实际上是满足题意的。此时的情况相当于物品中氧气的含量或者氮气的含量高于需要的含量。而此题要的就是等于或者高于需要的调济安都可行,所以w1 >= j 或者 w2 >= k 是满足条件的。
这个时候就相当于f[i - 1][0][...]或者f[i - 1][...][0]然后使用这个w1>=j或者w2>=k的这个物品。
所以代码中会发现后面跟两个for()循环都从m/n 遍历到了 0/0. 无需到w1[i]/w2[i]就停止。
for(int i = 1 ; i <= k ; i++)
{
for(int j = m ; j >= 0 ; j--)
{
for(int t = n ; t >= 0 ; t--)
{
f1[j][t] = min(f1[j][t] , f1[max(0,j - w1[i])][max(0,t - w2[i])] + v[i]);
}
}
}
其中有关初始化时的总结:
参考文献:https://www.acwing.com/blog/content/458/
初始化总结1:(由于后面的状态f[i][j]是由f[i -1][]进行更新而来,所以无需对f[1~i][j]进行初始化,初始化时对f[0][0~m]进行初始化即可)
2.求方案数初始化总结
二维情况
1、体积至多j,f[0][j (0~m) ] = 1, 0 <= j <= m,其余是0. 我的理解:因为体积至多是j包含了为0的情况。而前0个物品只能使得体积为0.所以方案数为1.而其余是0是因为f[ (非0) ][]由f[0][]更新而来即可。
2、体积恰好j,f[0][0] = 1, 其余是0。 我的理解:因为物品为前0个,只能组成体积恰好为0的情况,其他的都不行。所以f[0][0] = 0.
3、体积至少j,f[0][0] = 1,其余是0 同恰好j.
一维情况
1、体积至多j,f[i] = 1, 0 <= i <= m,
2、体积恰好j,f[0] = 1, 其余是0
3、体积至少j,f[0] = 1,其余是0
3.求最大值最小值初始化总结
二维情况
1、体积至多j,f[i,k] = 0,0 <= i <= n, 0 <= k <= m(只会求价值的最大值)
2、体积恰好j,
当求价值的最小值:f[0][0] = 0, 其余是INF.
我的理解:
f[0][非0]为INF代表无法到达此种情况。只有f[0][0]可以到达,价值为0. 而无法到达初始化为INF是因为求最小值后面f[i][j] = min(f[i - 1][j],f[i - 1][j - w] + v ..)
当求价值的最大值:f[0][0] = 0, 其余是-INF
3、体积至少j,f[0][0] = 0,其余是INF(只会求价值的最小值)
一维情况
1、体积至多j,f[i] = 0, 0 <= i <= m(只会求价值的最大值)
2、体积恰好j,
当求价值的最小值:f[0] = 0, 其余是INF
当求价值的最大值:f[0] = 0, 其余是-INF
3、体积至少j,f[0] = 0,其余是INF(只会求价值的最小值)
代码实现:
# include <iostream>
# include <cstring>
using namespace std;
const int M = 25 , N = 85 , K = 1010;
// int f[K][M][N]; //三维
int f1[M][N]; // 二维
int w1[K],w2[K],v[K];
int m,n,k;
int main()
{
scanf("%d %d %d",&m,&n,&k);
for(int i = 1 ; i <= k ; i++)
{
scanf("%d %d %d",&w1[i],&w2[i],&v[i]);
}
/* // 三维
memset(f,0x3f,sizeof f);
f[0][0][0] = 0;
for(int i = 1 ; i <= k ; i++)
{
for(int j = 0 ; j <= m ; j++)
{
for(int t = 0 ; t <= n ; t++)
{
f[i][j][t] = min(f[i - 1][j][t] , f[i - 1][max(0,j - w1[i])][max(0,t - w2[i])] + v[i]);
}
}
}
printf("%d\n",f[k][m][n]);*/
// 二维
memset(f1,0x3f,sizeof f1);
f1[0][0] = 0;
for(int i = 1 ; i <= k ; i++)
{
for(int j = m ; j >= 0 ; j--)
{
for(int t = n ; t >= 0 ; t--)
{
f1[j][t] = min(f1[j][t] , f1[max(0,j - w1[i])][max(0,t - w2[i])] + v[i]);
}
}
}
printf("%d\n",f1[m][n]);
return 0;
}