暑假N天乐 —— 多重+分组背包及变形

[HDU-1114 Piggy-Bank] 完全背包裸题

http://acm.hdu.edu.cn/showproblem.php?pid=1114

一道迷路的完全背包跑到了这里来...相当于给定背包大小,然后问装满之后最多的价值。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 1e4+5;

int val[505], w[505];
int dp[maxn];

int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		int a, b, n, m;
		scanf("%d%d", &a, &b);
		n = b-a;
		scanf("%d", &m);
		for(int i = 1; i <= m; i++) {
			scanf("%d%d", &val[i], &w[i]);
		}
		memset(dp, inf, sizeof(dp));
		dp[0] = 0;
		for(int i = 1; i <= m; i++) {
			for(int j = w[i]; j <= n; j++) {
				dp[j] = min(dp[j], dp[j-w[i]]+val[i]);
			}
		}
		if(dp[n] == inf) {
			printf("This is impossible.\n");
		}
		else {
			printf("The minimum amount of money in the piggy-bank is %d.\n", dp[n]);
		}
	}
	return 0;
}

[HDU-1059 Dividing] 多重背包裸题

http://acm.hdu.edu.cn/showproblem.php?pid=1059

给定 1~6 这六个数的数量,问能不能把这些数分成价值相同的两堆。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 2e5+5;

int val[7], num[7];
int dp[maxn];

int main() {
	for(int i = 1; i <= 6; i++) {
		val[i] = i;
	}
	int cas = 1;
	while(~scanf("%d%d%d%d%d%d", &num[1], &num[2], &num[3], &num[4], &num[5], &num[6])) {
		if(num[1]+num[2]+num[3]+num[4]+num[5]+num[6] == 0) {
			break;
		}
		printf("Collection #%d:\n", cas++);
		int sum = 0;
		for(int i = 1; i <= 6; i++) {
			sum += (num[i]*val[i]);
		}
		if(sum % 2 == 1) {
			printf("Can't be divided.\n\n");
			continue;
		}
		sum = sum/2;
		memset(dp, 0, sizeof(dp));
		for(int i = 1; i <= 6; i++) {
			if(val[i]*num[i] >= sum) {
				for(int j = val[i]; j <= sum; j++) {
					dp[j] = max(dp[j], dp[j-val[i]]+val[i]);
				}
			}
			else {
				int k = 1;
				while(k < num[i]) {
					for(int j = sum; j >= k*val[i]; j--) {
						dp[j] = max(dp[j], dp[j-k*val[i]]+k*val[i]);
					}
					num[i] -= k;
					k *= 2;
				}
				for(int j = sum; j >= num[i]*val[i]; j--) {
					dp[j] = max(dp[j], dp[j-num[i]*val[i]]+num[i]*val[i]);
				}
			}
		}
		if(dp[sum] == sum) {
			printf("Can be divided.\n\n");
		}
		else {
			printf("Can't be divided.\n\n");
		}
	}
	return 0;
}

[HDU-2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活] 多重背包裸题

http://acm.hdu.edu.cn/showproblem.php?pid=2191

买米,给定每种米的价格、价值和数量,问给你的钱最多能买到多少价值的米。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int v[105], w[105], c[105];
int dp[105];

int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		int n, m;
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= m; i++) {
			scanf("%d%d%d", &v[i], &w[i], &c[i]);
		}
		memset(dp, 0, sizeof(dp));
		for(int i = 1; i <= m; i++) {
			if(v[i]*c[i] >= n) {
				for(int j = v[i]; j <= n; j++) {
					dp[j] = max(dp[j], dp[j-v[i]]+w[i]);
				}
			}
			else {
				int k = 1;
				while(k < c[i]) {
					for(int j = n; j >= k*v[i]; j--) {
						dp[j] = max(dp[j], dp[j-k*v[i]]+k*w[i]);
					}
					c[i] -= k;
					k *= 2;
				}
				for(int j = n; j >= c[i]*v[i]; j--) {
					dp[j] = max(dp[j], dp[j-c[i]*v[i]]+c[i]*w[i]);
				}
			}
		}
		printf("%d\n", dp[n]);
	}
	return 0;
}

[POJ-1276 Cash Machine] 多重背包裸题

http://poj.org/problem?id=1276

题意...记不太得了..反正是裸题就对了。不想上代码了。

[POJ-2392 Space Elevator] 多重背包变形

http://poj.org/problem?id=2392

给定几种砖块,每种砖块都有自己的高度、数量和超过xx高度就不能用的属性(ai)。问最高能叠到多少。

在传统多重背包的基础上,需要按照 ai 排序,又因为不定最大值,所以需要给定理论上界来进行循环,就这样。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

struct node {
	int h, a, c;
	bool operator < (const node &y) const {
		return a < y.a;
	}
}x[405];

int dp[40005];

int main() {
	int n;
	while(~scanf("%d", &n)) {
		for(int i = 1; i <= n; i++) {
			scanf("%d%d%d", &x[i].h, &x[i].a, &x[i].c);
		}
		sort(x+1, x+1+n);
		memset(dp, 0, sizeof(dp));
		for(int i = 1; i <= n; i++) {
			if(x[i].h*x[i].c > 40000) {
				for(int j = x[i].h; j <= 40000; j++) {
					if(j > x[i].a)
						break;
					dp[j] = max(dp[j], dp[j-x[i].h]+x[i].h);
				}
			}
			else {
				int k = 1;
				while(k < x[i].c) {
					for(int j = 40000; j >= k*x[i].h; j--) {
						if(j > x[i].a)
							continue;
						dp[j] = max(dp[j], dp[j-k*x[i].h]+k*x[i].h);
					}
					x[i].c -= k;
					k *= 2;
				}
				for(int j = 40000; j >= x[i].h*x[i].c; j--) {
					if(j > x[i].a)
						continue;
					dp[j] = max(dp[j], dp[j-x[i].h*x[i].c]+x[i].h*x[i].c);
				}
			}
		}
		int ans = 0;
		for(int i = 40000; i >= 0; i--) {
			if(dp[i] == i) {
				ans = i;
				break;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

[HDU-1712 ACboy needs your help] 分组背包裸题

http://acm.hdu.edu.cn/showproblem.php?pid=1712

有 m 天复习 n 门课程,每天只能复习一门课。并且给定课程 i 复习 j 天获得的价值,问最多能获得多少价值。

分组背包顾名思义,在背包里面的物品是分成不同组的,每个组只能取一件物品。类似于01背包的做法,很容易想到,背包的容量一定是从大到小递推才能保证每组物品只取一个。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int a[105][105];
int dp[105];

int main() {
	int n, m;
	while(~scanf("%d%d", &n, &m)) {
		if(n+m == 0) {
			break;
		}
		memset(a, 0, sizeof(a));
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= m; j++) {
				scanf("%d", &a[i][j]);
			}
		}
		memset(dp, 0, sizeof(dp));
		for(int i = 1; i <= n; i++) {
			for(int j = m; j >= 0; j--) {
				for(int k = 1; k <= j; k++) {
					dp[j] = max(dp[j], dp[j-k]+a[i][k]);
				}
			}
		}
		printf("%d\n", dp[m]);
	}	
	return 0;
}

[HDU-3033 I love sneakers!] 分组背包变形

http://acm.hdu.edu.cn/showproblem.php?pid=3033

买球鞋,给定球鞋数量 n、支付宝金额 m、球鞋种类 k。每双球鞋都有种类、价值、花费。要求是每种球鞋都要至少买一个,求最大价值。

分组背包问题一般是每组最多选一件,这里是选至少一件,我们需要对每组进行01背包。当前第 k 组的时候在里面选择物品的时候是选的第几件。如果我们当前是选第 k 组中的第一件,那么是从第 k-1 组推过来的;否则就是第 k 组中的前一件 (i-1) 推过来的。初始化是,如果一开始把 dp 初始化为0,则当所有鞋子的价值都是 0 时,就无法区分是买不全那几款鞋子还是能买全但最大价值是0。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 1e4+5;

int dp[105][maxn];  // dp[k][i] 表示前 k 组中花费 i 取得的最大价值
int b[105], w[105], v[105];

int main() {
	int n, m, k;
	while(~scanf("%d%d%d", &n, &m, &k)) {
		for(int i = 1; i <= n; i++) {
			scanf("%d%d%d", &b[i], &w[i], &v[i]);
		}
		memset(dp, -1, sizeof(dp));
		for(int i = 0; i <= m; i++) {
			dp[0][i] = 0;
		}
		for(int x = 1; x <= k; x++) {
			for(int i = 1; i <= n; i++) {
				if(b[i] == x) {
					for(int j = m; j >= w[i]; j--) {
						dp[x][j] = max(dp[x][j], max(dp[x][j-w[i]]+v[i], dp[x-1][j-w[i]]+v[i]));
					}
				}
			}
		}
		if(dp[k][m] == -1) {
			printf("Impossible\n");
		}
		else {
			printf("%d\n", dp[k][m]);
		}
	}
	return 0;
}

[POJ-1837 Balance] 分组背包变形

http://poj.org/problem?id=1837

输入 n 表示天平上有几个挂钩、m 表示有几个挂码。给定每个挂钩的位置(a),负数表示在左侧,正数表示在右侧。给定每个挂码的重量(b)。问有几种方法可以使得天平平衡。

由数据范围可知,天平左右两端力矩最大值都是 201525=7500。因此用[0, 15000] 表示力矩的范围,7500表示平衡状态。初始化0个砝码时,到达平衡状态7500时的方案数为1。

达到每种状态时的方案数,需要从 1 个挂码到有 m 个挂码的状态进行转移。因此可以类似背包问题的方法求解,有状态转移方程 \(dp[i][j+b[i]*a[k]] += dp[i-1][j]\)
表示第 i 个砝码是新加入的,砝码 i 悬挂的位置用 k 表示有1~n个。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 20*15*25*2+5;

int a[25], b[25];	// a 挂钩位置、b 物体重量
int dp[25][maxn];

int main() {
	int n, m;
	while(~scanf("%d%d", &n, &m)) {
		for(int i = 1; i <= n; i++) {
			scanf("%d", &a[i]);
		}
		for(int i = 1; i <= m; i++) {
			scanf("%d", &b[i]);
		}
		memset(dp, 0, sizeof(dp));
		dp[0][7500] = 1;
		for(int i = 1; i <= m; i++) {
			for(int j = 1; j <= 15000; j++) {
				for(int k = 1; k <= n; k++) {
					dp[i][j+a[k]*b[i]] += dp[i-1][j];
				}
			}
		}
		printf("%d\n", dp[m][7500]);
	}
	return 0;
}

[POJ-3211 Washing Clothes] 分组背包变形

http://poj.org/problem?id=3211

先记录每种颜色所代表的衣服洗干净所用的时间。对于第 i 颜色,用01背包找到0到 sum[i]/2 ,洗衣服时可能遇到所有时间点,在找到 0 到 sum[i]/2 中最大的时间点 j ,则 sum[i]-j 则是洗第 i 种颜色的衣服所用的最少时间。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

string s[15];
int cnt[15], sum[15];
int t[15][105];
int dp[50005];

int main() {
	int n, m;
	while(~scanf("%d%d", &n, &m)) {
		if(n+m == 0) {
			break;
		}
		memset(cnt, 0, sizeof(cnt));
		memset(sum, 0, sizeof(sum));
		memset(t, 0, sizeof(t));
		for(int i = 1; i <= n; i++) {
			cin >> s[i];
		}
		for(int i = 1; i <= m; i++) {
			int a;
			string str;
			cin >> a >> str;
			for(int j = 1; j <= n; j++) {
				if(str == s[j]) {
					t[j][cnt[j]] = a;	
					sum[j] += a;
					cnt[j] ++;
					break;
				}
			}
		}
		int ans = 0;
		for(int i = 1; i <= n; i++) {
			memset(dp, 0, sizeof(dp));
			dp[0] = 1;
			for(int j = 0; j < cnt[i]; j++) {
				for(int k = sum[i]/2; k >= t[i][j]; k--) {
					dp[k] |= dp[k-t[i][j]];
				}
			}
			int temp;
			for(temp = sum[i]/2; temp >= 0; temp--) {
				if(dp[temp]) {
					break;
				}
			}
			temp = sum[i] - temp;
			ans += temp;
		}
		printf("%d\n", ans);
	}
	return 0;
}

[HDU-3810 Magina] 分组背包 + 双优先队列优化

http://acm.hdu.edu.cn/showproblem.php?pid=3810

dota敌法师的技能闪烁无CD。他现在要刷野区赚钱,每个野怪营地需要花费 t 时间赚取 g 赏金。存在一些点之间可以用闪烁技能到达。问能否在赚到给定金钱,并求出最小时间。

把能够相互到达的点可以看成一部分,那么就分成很多部分,每个部分没有任何联系,相互做一次01背包,取最小值就行。

问题的关键是本题数据很大,背包容量最大是10亿,虽然给了30s,但是数组和普通队列都存不下。所以需要剪枝,比如说时间都已经超过了中间临时的最小时间的,肯定不用继续搜下去了,还有当前容量占用小,时间花费长的肯定要剪掉,那么一个好的方法是优先队列,可以很方便的剪掉刚才说的第二种无用状态。

故用两个优先队列,类似与滚动数组的思路,第一个存放当前状态,第二个存放能够转移得到的状态,然后再把转移得到的状态剪掉一部分后放回第一个队列。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 55;

int cnt[maxn], vis[maxn];
int road[maxn][maxn];
int mp[maxn][maxn];
int n, m, ans;
int tot;

struct NODE {
	int t, g;
	bool operator < (const NODE &a) const {
		if(g == a.g) {
			return t > a.t;
		}
		return g < a.g;
	}
}node[maxn];

void init() {
	memset(mp, 0, sizeof(mp));
	memset(cnt, 0, sizeof(cnt));
	memset(vis, 0, sizeof(vis));
	memset(road, 0, sizeof(road));
	ans = inf;
	tot = 0;
}

void dfs(int x) {
	for(int i = 1; i <= n; i++) {
		if(vis[i] == 0 && mp[x][i] == 1) {
			vis[i] = 1;
			road[tot][cnt[tot]++] = i;
			dfs(i);
		}
	}
}

void solve() {
	for(int i = 0; i < tot; i++) {
		priority_queue<NODE> q1, q2;
		NODE now, nxt;	
		now.t = now.g = 0;
		q1.push(now);
		for(int j = 0; j < cnt[i]; j++) {
			while(!q1.empty()) {
				now = q1.top();
				q1.pop();
				q2.push(now);
				nxt.t = now.t + node[road[i][j]].t;
				nxt.g = now.g + node[road[i][j]].g;
				if(nxt.g >= m) {
					ans = min(ans, nxt.t);
				}
				else if(nxt.t < ans) {
					q2.push(nxt);
				}
			}
			int temp = inf;
			while(!q2.empty()) {
				now = q2.top();
				q2.pop();
				if(temp >= now.t) {
					q1.push(now);
					temp = now.t;
				}
			}
		}
	}
}

int main() {
	int t, cas = 1;
	scanf("%d", &t);
	while(t--) {
		init();
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; i++) {
			int x;
			scanf("%d%d%d", &node[i].t, &node[i].g, &x);
			for(int j = 1; j <= x; j++) {
				int y;
				scanf("%d", &y);
				mp[i][y] = mp[y][i] = 1;
			}
		}
		for(int i = 1; i <= n; i++) {
			if(vis[i] == 0) {
				vis[i] = 1;
				road[tot][cnt[tot]++] = i;
				dfs(i);
				tot++;
			}
		}
		solve();
		printf("Case %d: ", cas++);
		if(ans == inf) {
			printf("Poor Magina, you can't save the world all the time!\n");
		}
		else {
			printf("%d\n", ans);
		}
	}
	return 0;
}

[HDU-3535 AreYouBusy] 综合背包

http://acm.hdu.edu.cn/showproblem.php?pid=3535

n 种工作集合、给 t 时间。工作集合分为 3 类(s =【0至少做一件】、【1至多做一件】、【2无限制】),每种集合有 m 个事件(用时 w、价值 v)。求能获得的最大价值。

用背包思想单独处理每个集合。\(dp[i][j]==x\) 表示处理完前 i 组工作集合,所花时间 <=j 时的快乐值为 x 。

  1. 至少做一件:要保证至少选 1 个第 i 类事件,可以从第 i-1 类的结果 dp[i-1] 来更新 dp[i] ;也可以从本类的前一个事件更新后一个事件。初始化:\(dp[i] = -inf\)。状态转移方程:

    \[dp[i][k] = max(dp[i][k], max(dp[i][k-w[j]]+v[j], dp[i-1][k-w[j]]+v[j])) \]

  2. 至多做一件:只能从 dp[i-1] 来更新 dp[i] 。初始化:\(dp[i]=dp[i-1]\)。状态转移方程:
    $$dp[i][k] = max(dp[i][k], dp[i-1][k-w[j]]+v[j])$$

  3. 无限制:初始化:\(dp[i]=dp[i-1]\)。状态转移方程:

    \[dp[i][k] = max(dp[i][k], dp[i][k-w[j]]+v[j]) \]

最终所求:\(dp[n][t]\)

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 1e2+5;

int dp[maxn][maxn];
int w[maxn], v[maxn];

int main() {
	int n, t;
	while(~scanf("%d%d", &n, &t)) {
		memset(dp, 0, sizeof(dp));
		for(int i = 1; i <= n; i++) {
			int m, s;
			scanf("%d%d", &m, &s);
			for(int j = 1; j <= m; j++) {
				scanf("%d%d", &w[j], &v[j]);
			}
			if(s == 0) {		// 至少选择一个做
				for(int j = 0; j <= t; j++) {
					dp[i][j] = -inf;
				}
				for(int j = 1; j <= m; j++) {
					for(int k = t; k >= w[j]; k--) {
						dp[i][k] = max(dp[i][k], max(dp[i][k-w[j]]+v[j], dp[i-1][k-w[j]]+v[j]));
					}
				}
			}
			else if(s == 1) {	// 至多选择一个做
				for(int j = 0; j <= t; j++) {
					dp[i][j] = dp[i-1][j];
				}
				for(int j = 1; j <= m; j++) {
					for(int k = t; k >= w[j]; k--) {
						dp[i][k] = max(dp[i][k], dp[i-1][k-w[j]]+v[j]);
					}
				}
			}
			else {				// 随便选
				for(int j = 0; j <= t; j++) {
					dp[i][j] = dp[i-1][j];
				}
				for(int j = 1; j <= m; j++) {
					for(int k = t; k >= w[j]; k--) {
						dp[i][k] = max(dp[i][k], dp[i][k-w[j]]+v[j]);
					}
				}				
			}
		}
		int ans = -1;
		ans = max(dp[n][t], ans);
		printf("%d\n", ans);
	}
	return 0;
}
posted @ 2019-07-16 20:08  Decray  阅读(165)  评论(0)    收藏  举报