CodeForces 632E Thief in a Shop

题目链接

(完全背包+思维)

题意:给你一个n和k,分别表示一共有n种物品(每种都有无限个),你的背包可以装下k个(且必须装满),随后给出n个数a[i]表示每种物品的价值,要求输出能装出的所有价值的情况。

题解:从题意可以知道我们可以装的价值情况在(最小价值物品)min_x * k 到 (最大价值物品) max_x * k 之间,不难想到这是一道完全背包问题(物品无限),那么如何转换到完全背包呢?这里我们只需要对每个物品的价值a[i] 减去 min_x 即可,那么我们的背包就是从0开始的了。定义dp[i]表示价值为i的物品所需要的最少物品(只有能装的越多才可能价值越大)且这里的i的范围就是max_x * k了,运行一波完全背包,取出dp[i]<=k的就是答案了(因为初始状态的0是全都是最小价值的情况,你最多只能通过替换k次去得到其他答案;也可以理解为当dp[i]<k时,说明该情况可以获得,剩余的用min_x来补),最后输出加上min_x*k即可。

代码如下:

#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdio>
#include<time.h>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = 1e6 + 500;
int a[maxn];
int dp[maxn];
vector<int>ans;
int main() {
	int n, k;
	while (~scanf("%d%d", &n, &k)) {
		ans.clear();
		for (int i = 0; i < n; i++)
			scanf("%d", &a[i]);
		sort(a, a + n);
		n = unique(a, a + n) - a;//去重
		int min_x = a[0];
		for (int i = 0; i < n; i++)//都减去min_x得到的答案范围就0~k*(max_x-min_x)内的完全背包的所有答案
			a[i] -= min_x;
		int max_x = a[n - 1];
		for (int i = 1; i <= max_x*k; i++)//完全背包2:需要刚好装满的初始化方法
			dp[i] = inf;
		dp[0] = 0;
		for (int i = 1; i < n; i++)
			for (int j = a[i]; j <= max_x*k; j++)
				dp[j] = min(dp[j], dp[j - a[i]] + 1);
		for (int i = 0; i <= max_x*k; i++)//当dp[i]<k时,说明该情况可以获得,剩余的用min_x来补
			if (dp[i] <= k) ans.push_back(min_x*k + i);
		for (int i = 0; i < ans.size(); i++)
			printf("%d%c", ans[i], (i == ans.size() - 1) ? '\n' : ' ');
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/80382493
今日推荐