题目描述
Joe觉得云朵很美,决定去山上的商店买一些云朵。
商店里有 朵云,云朵被编号为 ,并且每朵云都有一个价值。
但是商店老板跟他说,一些云朵要搭配来买才好,所以买一朵云则与这朵云有搭配的云都要买。
但是Joe的钱有限,所以他希望买的价值越多越好。
输入格式
第 行包含三个整数 ,表示有 朵云, 个搭配,Joe有 的钱。
第 行,每行两个整数 , 表示 朵云的价钱和价值。
第 行,每行两个整数 ,表示买 就必须买 ,同理,如果买 就必须买 。
输出格式
一行,表示可以获得的最大价值。
数据范围
,
,
,
,
,
,
输入样例:
5 3 10
3 10
3 10
3 10
5 100
10 1
1 3
3 2
4 2
输出样例:
1
题目分析
本题的解题思路是先用 并查集 将物品重新分类,然后再用 01背包 选择物品。
分析题目,每个物品可看作拥有体积 和价值 ,Joe 则拥有一个体积为 的背包,相较于一般的01背包,本题主要是将一些物品归为一个物品,其中体积以及价值均求和。
接下来,我们便可以使用并查集的思想,将有联系的物品的性质累加到这条关系链中的一个物品之上,注意每个物品对此关系链的根节点的贡献只有一次。
然后再利用01背包的思想,枚举所有物品链的根节点 ,对其进行选择。
最终复杂度为 。
Accept代码
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
int n, q, m;
int v[N], w[N];
int p[N], f[N];
int find(int x)
{
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> q >> m;
for (int i = 1; i <= n; i ++) cin >> v[i] >> w[i], p[i] = i;
while (q --)
{
int a, b;
cin >> a >> b;
a = find(a), b = find(b);
if (a == b) continue;
p[b] = a;
w[a] += w[b];
v[a] += v[b];
}
for (int i = 1; i <= n; i ++)
{
if (find(i) != i) continue;
// cout << i << ' ' << v[i] << ' ' << w[i] << "\n";
for (int j = m; j >= v[i]; j --)
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
cout << f[m];
return 0;
}
碎碎念
下午时,坐在宿舍阳台上,听着校园的广播,云朵确实很美~
只是不知道这样的日子还有多少