http://acm.hdu.edu.cn/showproblem.php?pid=2159
10 10 1 10 1 1 10 10 1 9 1 1 9 10 2 10 1 1 2 2
0 -1 1
二维的背包问题是指对于每种代价都有一个可付出的最大值,具有两种不同的费用,选择这种物品必须同时付出这两种代价,第i件物品所需的两种代价分别为a[i]和 b[i],两种代价可付出的最大值(两种背包容量)分别为V和U。物品的价值为w[i];
状态转移方程为f[i][v][u] = max (f[i][v][u], f[i-1][v-a[i]][u-b[i]]+w[i]);
如上述方法,可以只使用二维数组,当每件物品只可以取一次的时候变量V和U采取逆序循环,当物品犹如完全背包问题时变量V和U采取顺序循环,当物品犹如多重背包时拆分物品。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <cstdlib> #include <limits> #include <queue> #include <stack> #include <vector> #include <map> using namespace std; #define N 800 #define INF 0x3f3f3f3f #define PI acos (-1.0) #define EPS 1e-8 #define met(a, b) memset (a, b, sizeof (a)) #define Lson rt<<1, l, tree[rt].mid() #define Rson rt<<1|1, tree[rt].mid()+1, r typedef long long LL; int dp[N][N]; int main () { int n, m, k, s, a[N], b[N]; while (scanf ("%d %d %d %d", &n, &m, &k, &s) != EOF) { int i, j, flag = 0; met (dp, 0); for (i=1; i<=k; i++) scanf ("%d %d", &a[i], &b[i]); for (i=1; i<=m; i++) { for (j=1; j<=s; j++) { for (int id=1; id<=k; id++) if (i >= b[id]) dp[i][j] = max (dp[i][j], dp[ i-b[id] ][j-1]+a[id]); } if (dp[i][s] >= n) { flag = 1; break; } } if (flag) printf ("%d\n", m-i); else puts ("-1"); } return 0; }