问题引入
有两种物品捆绑销售,每种包装里两种物品各有 x , y x,y x,y个,售价为 t t t元,共有 s s s个捆绑销售的包装。现在需要两种物品 n , m n,m n,m个,问如何购买可以满足需要并且花费最少的钱
状态转移
设 d [ i ] [ j ] d[i][j] d[i][j]表示第一、二种物品分别买了 i , j i,j i,j个的最小花费,那么状态转移方程为:
d [ i ] [ j ] = m i n ( d [ i ] [ j ] , d [ i − x ] [ j − y ] + t ) d[i][j]=min(d[i][j],d[i-x][j-y]+t) d[i][j]=min(d[i][j],d[i−x][j−y]+t)
边界处理
但是这里需要注意的是,不难发现 i − x , j − y i-x,j-y i−x,j−y需要大于等于 0 0 0,按照习惯应该写:
for (int i = 0, x, y, t; i < s; i++) {
cin >> x >> y >> t;
for (int j = n; j >= x; j--)
for (int k = m; k >= y; k--)
d[j][k] = min(d[j][k], d[j - x][k - y] + t);
}
但是这样是错误的,原因是如果这样写就变成了恰好拿 n , m n,m n,m个物品,而本题对上界没有要求,那么也就是说当背包容量溢出后,在状态转移时实际上变成了负值,那么我们都从 d [ 0 ] [ 0 ] d[0][0] d[0][0]这个状态转移即可:
for (int i = 0, x, y, t; i < s; i++) {
cin >> x >> y >> t;
for (int j = n; j >= 0; j--)
for (int k = m; k >= 0; k--)
d[j][k] = min(d[j][k], d[max(j - x, 0)][max(k - y, 0)] + t);
}
初始化
d [ 0 ] [ 0 ] = 0 d[0][0]=0 d[0][0]=0,其余均为 i n f inf inf
代码
int s, n, m;
cin >> s >> n >> m;
memset(d, 0x3f, sizeof d);
d[0][0] = 0;
for (int i = 0, x, y, t; i < s; i++) {
cin >> x >> y >> t;
for (int j = n; j >= 0; j--)
for (int k = m; k >= 0; k--)
d[j][k] = min(d[j][k], d[max(j - x, 0)][max(k - y, 0)] + t);
}
cout << d[n][m] << ENDL;