题目描述:
明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有n nn朵云,云朵已经被老板编号为1 , 2 , 3 , . . . , n 1,2,3,...,n1,2,3,...,n,并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉得这礼物实在是太新奇了,但是你的钱是有限的,所以你肯定是想用现有的钱买到尽量多价值的云。
题目思路:
这段程序是一个使用并查集和01背包求解多重背包问题的实现。具体来说,它首先通过并查集将商品划分为不同的组,然后计算每组搭配购买的总花费和总价值,并将其转化为多个01背包问题,最后用动态规划求解得到最大总价值。
程序主要包括三个操作:
-
并查集操作:当输入两个商品 x 和 y 的时候,将它们所在的组合并成一个组。具体来说,程序通过调用 find() 函数找到 x 和 y 所在的组的代表元素 fx 和 fy,然后将 father[fy] 设为 fx,表示将 fy 所在的组合并到 fx 所在的组中。
-
计算操作:在合并操作中,我们还需要计算每个组搭配购买的总花费和总价值。具体来说,程序在合并 fx 和 fy 组时,将 w[fx] 和 v[fx] 分别加上 w[fy] 和 v[fy],表示将 fy 组中的商品搭配到 fx 组中。
-
01背包求解操作:对于每个组,我们可以将其搭配购买的商品视为一个01背包问题,其中物品的重量为 w[i],价值为 v[i]。程序使用动态规划求解每个01背包问题的最大总价值 f[j],并在得到所有组的最大总价值后输出它们的和。
#include<cstdio>
#include<iostream>
using namespace std;
int n, m, val, w[10001], f[10001], v[10001], tot, x, y, father[10001], i, j;
int find(int x)//查找根节点
{
if (father[x] != x)
father[x] = find(father[x]);
return father[x];
}
int main()
{
cin >> n >> m >> val;
for (i = 1; i <= n; i++)
{
cin >> w[i] >> v[i];
father[i] = i;
//初始化集合,以每个元素作为自己的根节点
}
for (i = 1; i <= m; i++)
{
cin >> x >> y;
int fx = find(x), fy = find(y);
if (fx != fy)
father[fy] = fx, w[fx] += w[fy], v[fx] += v[fy];
//先将每组搭配购买的总花费、总价值算出来
}
for (i = 1; i <= n; i++)
if (father[i] == i)
{
v[++tot] = v[i];
w[tot] = w[i];
}
for (i = 1; i <= tot; i++)//01背包求解
for (j = val; j >= w[i]; j--)
f[j] = max(f[j], f[j - w[i]] + v[i]);
cout << f[val] << endl;
return 0;
}