CF741B:https://codeforces.com/problemset/problem/741/B

从0开始学算法發表於2024-04-26

題目描述

大意就是若干人組成某一個連通塊,對於每一個人都有一個代價v,和一個魅力值b,選的時候一個集合要麼選一個,要麼全選,要麼不選,求解代價不超過w的前提下所能得到的最大魅力值。
那麼我們可以得知這是一道很明顯的分組揹包問題,關鍵是用並查集預處理每一物品組

樣例

input:
3 1 5
3 2 5
2 4 2
1 2
output:
6

演算法1

(dp+並查集) $O(nm)$

C++ 程式碼

#include<bits/stdc++.h>
using i64=long long;
struct DSU{
    std::vector<int>f,siz;
    DSU(){};
    DSU(int n){
        init(n);
    }
    void init(int n){
        f.resize(n);
        std::iota(f.begin(),f.end(),0);
        siz.assign(n,1);
    }
    int find(int x){
        return f[x]==x?x:find(f[x]);
    }
    bool same(int x,int y){
        return find(x)==find(y);
    }
    bool merge(int x,int y){
        x=find(x),y=find(y);
        if(x==y){
            return false;
        }
        if(siz[x]<siz[y]){
            std::swap(x,y);
        }
        siz[x]+=siz[y];
        f[y]=x;
        return true;
    }
    int size(int x){
        return siz[find(x)];
    }
};
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n,m,w;
    std::cin>>n>>m>>w;
    std::vector<int>v(n),b(n);
    for(auto &x:v){
        std::cin>>x;
    }
    for(auto &x:b){
        std::cin>>x;
    }
    DSU dsu(n);
    while(m--){
        int x,y;
        std::cin>>x>>y;
        x--,y--;
        dsu.merge(x,y);
    }
    std::vector<int>g[n];
    for(int i=0;i<n;i++){
        g[dsu.find(i)].push_back(i);
    }
    std::vector<i64>dp(w+1,0);
    for(int i=0;i<n;i++){
        if(dsu.find(i)!=i){
            continue;
        }
        for(int j=w;j>=0;j--){
            int cost=0,val=0;
            for(auto k:g[i]){
                cost+=v[k];
                val+=b[k];
                if(j>=v[k]){
                    dp[j]=std::max(dp[j],dp[j-v[k]]+b[k]);
                }
            }
            if(j>=cost){
                dp[j]=std::max(dp[j],dp[j-cost]+val);
            }
        }
    }
    std::cout<<dp[w]<<"\n";
    return 0;
}

相關文章