【01背包 合并费用】搭配购买
传送门
题意
给定\(n\)朵云,编号\(1,2\dots ,n\),每个云朵有一个价格\(c_{i}\),价值\(d_{i}\),
一共有\(w\)的钱,一共\(m\)对关系\((u_{i},v_{i})\)表示\((u_{i},v_{i})\)需要一起购买,求最大价值
数据范围
\(\begin{array}{l}1 \leq n \leq 10000 \\ 0 \leq m \leq 5000 \\ 1 \leq w \leq 10000 \\ 1 \leq c_{i} \leq 5000 \\ 1 \leq d_{i} \leq 100 \\ 1 \leq u_{i}, v_{i} \leq n\end{array}\)
题解
将所有需要合并的价值和价格都合并到一个集合中,最后对所有不同集合做\(01\)背包即可
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int n,m,w;
int fa[N],c[N],d[N],dp[N];
int find(int x){
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void merge(int a,int b){
int pa=find(a),pb=find(b);
if(pa!=pb) {
c[pb] += c[pa];
d[pb] += d[pa];
fa[pa] = pb;
}
}
int main(){
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=n;i++) fa[i] = i;
for(int i=1;i<=n;i++) scanf("%d%d",&c[i],&d[i]);
while(m--){
int u,v; scanf("%d%d",&u,&v);
merge(u,v);
}
for(int i=1;i<=n;i++){
if(fa[i] == i)
for(int j=w;j>=c[i];j--){
dp[j]=max(dp[j],dp[j-c[i]]+d[i]);
}
}
printf("%d\n",dp[w]);
}