題目描述
大意就是若干人組成某一個連通塊,對於每一個人都有一個代價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;
}