/*
乍看是一个简单的01背包,但是仔细看发现数据量很大,背包的数目相当大,
直接搞必定挂掉。
这时我们发现其中有个条件:Vi,Ci <= 10,
那么其实这么庞大的数量中有相当多数量的背包都是一样的:价值和重量都相等。
那么我们开一个二维数组CNT[][]第一维表示重量,第二维是价值,显然可以用
11*11大小的数组统计出来,现在就可以转化成一个多重背包了,而且根据这里的
分析我们可以肯定最后的背包数量不会多于121个,那么O(M*N)的复杂度就可以接受了,
后面按照多重背包搞就可以了:转化成01背包。
当然,空间上我们经过上面的分析也是O(M*N)的复杂度,至多百万级,可以接受。
优化一下当然更好.
*/
#include <cstdio>
#include <cstring>
#include <vector>
#include <utility>
using namespace std;
const int MAX = 10007;
int shot[11][11];
int dp[MAX];
vector<pair<int, int> > V;
int bag01(int RL) {
memset(dp, 0, sizeof(dp));
for (int i = 0; i < V.size(); ++i) {
for (int j = RL; j >= V[i].first; --j) {
if (dp[j - V[i].first] + V[i].second > dp[j]) {
dp[j] = dp[j - V[i].first] + V[i].second;
}
}
}
return dp[RL];
}
int main() {
int N, C;
char word[16];
while (~scanf(" %d %d", &N, &C)) {
memset(shot, 0, sizeof(shot));
int v, w;
for (int i = 0; i < N; ++i) {
scanf(" %s %d %d", word, &v, &w);
++shot[w][v];
}
V.clear();
for (int i = 0; i < 11; ++i) {
for (int j = 0; j < 11; ++j) {
//分解重量i,价值为j的物品
//分解的是个数,保存的是价值和重量
//pair<重量,价值>
//如(13,25)有13个, 分解为1, 2, 4, 6个
int n = 0, m = 1; //n记录总共消费的个数,m表示接下来要尝试拼的个数
while (shot[i][j] > n) {
if (n + m <= shot[i][j]) {
V.push_back(make_pair(m*i, m*j));
n += m;
m <<= 1; //如果拼成了1,下一步就要尝试2,然后4,8下去。。。
} else {
int tmp = shot[i][j] - n;
V.push_back(make_pair(tmp * i, tmp * j));
break;
//如果出现上例中的13个,那么试拼8个不成功,就会在这里拼6个
}
}
}
}
#ifndef ONLINE_JUDGE
for (int i = 0; i < V.size(); ++i) {
printf("%d ", V[i]);
}
puts("Did over.");
#endif
printf("%d\n", bag01(C));
}
return 0;
}
[hdu3732]dp-背包-转换
最新推荐文章于 2017-03-02 23:03:22 发布