潜水员
fi,j,k:表示 在前i个物品中进行选择,氧气含量最少为i,氮气含量至少为k的选择。
状态转移
f i j k = min(f(i-1,j,k) , f (i,j,-v1i,k-v2i)+wi)
和之前二维的模板不同的地方在于,这里的限制是至少为多少,所以负数也应该是合法的,但是要用0来表示,同时两个数j k中一个是0,而另一个不是0的情况也是存在的,所以也要有表示,但是在一个物品也没有的时候只有f00=0 其他都是无穷。
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f,N = 22,M = 80;
int f[N][M];
int main() {
int n,m,K;
cin>>n>>m>>K;
memset(f,INF,sizeof f);
f[0][0] = 0;
while(K--){
int v1,v2,w;
scanf("%d%d%d",&v1,&v2,&w);
for(int i = n;i>=0;i--){
for(int j = m;j>=0;j--){
f[i][j] = min(f[i][j],f[max(0,i-v1)][max(0,j-v2)]+w);
}
}
}
cout<<f[n][m];
return 0;
}
数字组合
思路:状态定义 fij 前i个数,总体积恰好为j的选法
状态转移:考虑不选第i个物品,则有fi-1,j个,考虑选择第i个则再加上f[i-1][j-v]
代码:
#include <iostream>
using namespace std;
const int N =1e4+10;
int f[N];
int a[105];
int main() {
int n,m;
cin>>n>>m;
for(int i = 1;i<=n;i++){
cin>>a[i];
}
f[0] = 1;
for(int i = 1;i<=n;i++){
for(int j = m;j>=a[i];j--){
f[j] = f[j]+f[j-a[i]];
}
}
cout<<f[m];
return 0;
}