输入输出样例
输入 #1复制
5 3 10 3 10 3 10 3 10 5 100 10 1 1 3 3 2 4 2
输出 #1复制
1
说明/提示
- 对于 30\%30% 的数据,满足 1 \le n \le 1001≤n≤100;
- 对于 50\%50% 的数据,满足 1 \le n,w \le 10^31≤n,w≤103,1 \le m \le 1001≤m≤100;
- 对于 100\%100% 的数据,满足 1 \le n \le 10^41≤n≤104,0 \le m \le 5 \times 10^30≤m≤5×103。
思路:这一题其实是由并查集和动态规划01背包结合起来的题目,难度适中吧.
相信学过并查集的应该很容易理解,我们现将每一个云朵的根节点设置为自身,然后输入搭配在一起的云朵,并将后面的棉花设置为前面的云朵的根节点(反过来也行哦),然后将根节点的云朵的总价格和总价值更新(加上搭配在一起的云朵的价格和价值)将所有搭配类型循环完之后,就可以套用01背包的模板了只不过加了一个约束条件,就是判断云朵是否属于根节点如果属于根节点则进行动态规划,不是根节点的话则进入下一个云朵。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
const int M = 5e3 + 5;
int c[N], d[N], dp[N], f[N];
int find(int x)
{
return f[x] == x ? x : f[x] = find(f[x]);//查找找根节点
}
int main()
{
ios::sync_with_stdio(false);//给cin提速 因为cin比scanf慢
cin.tie(0), cout.tie(0);
int n, m, w;
cin >> n >> m >> w;
for (int i = 1; i <= n; i++)
{
cin >> c[i] >> d[i];
f[i] = i;//令自身为根节点
}
int x, y;
for (int i = 1; i <= m; i++)
{
cin >> x >> y;
int u = find(x);//并查集合并
int v = find(y);
f[u] = v;
c[v] = c[u] + c[v];//将搭配的总价格和总价值放置于根节点处
d[u] = d[u] + d[v];
}
for (int i = 1; i <= n; i++)//搜寻根节点,如果为根节点则进行动态规划
{
if (f[i] == i)
{
for (int j = w; j >= c[i]; j--)
{
dp[j] = max(dp[j], dp[j - c[i]] + d[i]);
}
}
}
cout << dp[w];//输出最大的价值
return 0;
}