通天之分组背包
题目背景
直达通天路·小 A 历险记第二篇
题目描述
自 01 01 01 背包问世之后,小 A 对此深感兴趣。一天,小 A 去远游,却发现他的背包不同于 01 01 01 背包,他的物品大致可分为 k k k 组,每组中的物品相互冲突,现在,他想知道最大的利用价值是多少。
输入格式
两个数 m , n m,n m,n,表示一共有 n n n 件物品,总重量为 m m m。
接下来 n n n 行,每行 3 3 3 个数 a i , b i , c i a_i,b_i,c_i ai,bi,ci,表示物品的重量,利用价值,所属组数。
输出格式
一个数,最大的利用价值。
样例 #1
样例输入 #1
45 3
10 10 1
10 5 1
50 400 2
样例输出 #1
10
提示
0
≤
m
≤
1000
0 \leq m \leq 1000
0≤m≤1000,
1
≤
n
≤
1000
1 \leq n \leq 1000
1≤n≤1000,
1
≤
k
≤
100
1\leq k\leq 100
1≤k≤100,
a
i
,
b
i
,
c
i
a_i, b_i, c_i
ai,bi,ci 在 int
范围内。
原题
代码
#include <bits/stdc++.h>
using namespace std;
#define max_Heap(x) priority_queue<x, vector<x>, less<x>>
#define min_Heap(x) priority_queue<x, vector<x>, greater<x>>
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int m, n;
cin >> m >> n;
unordered_map<int, vector<int>> mp; // 离散化分组的存储
vector<int> weight(n);
vector<int> value(n);
int num; // 第几组
for (int i = 0; i < n; i++)
{
cin >> weight[i] >> value[i];
cin >> num;
mp[num].push_back(i); // 将物品序号保存在所在组内
}
// dp数组
vector<ll> dp(m + 1, 0);
// 遍历所有组
for (auto it = mp.begin(); it != mp.end(); it++)
{
num = it->first;
// 遍历背包
for (int i = m; i >= 0; i--)
{
// 遍历组内所有物品,以先遍历背包再遍历组内物品的顺序可以保证组内最多选一个物品
for (int j = 0; j < mp[num].size(); j++)
{
int idx = mp[num][j]; // 物品的序号
if (i >= weight[idx])
{
dp[i] = max(dp[i], dp[i - weight[idx]] + 1ll * value[idx]);
}
}
}
}
cout << dp[m];
return 0;
}