【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]);
}
posted @ 2020-08-03 15:27  Hyx'  阅读(143)  评论(0编辑  收藏  举报