分析
分组背包加并查集。
本题的并查集是最基本的满足传递性的朋友关系,所以直接合并即可。
然后用背包分组别进行运算,\(f[i]\) 表示计算了前面的组别后 \(i\) 的重量最多多少魅力值,\(g[i]\) 表示计算当前组后的对应答案,为保证分组正确性,避免在计算一个组时将单个个体计算多次,转移计算 \(g\) 时只能用 \(f\)。在计算完后再将 \(g\) 的答案更新给 \(f\)。
代码
#include<bits/stdc++.h>
using namespace std;
inline void read(int &res){
int f=1;
res=0;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=(res<<1)+(res<<3)+c-48,c=getchar();
res*=f;
}
int n,m,w;
int vis[1005];
int fa[1005];
int f[1005],g[1005];
int a[1005],b[1005];
inline int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
signed main()
{
read(n);read(m);read(w);
for(int i=1;i<=n;i++)read(a[i]),fa[i]=i;
for(int i=1;i<=n;i++)read(b[i]);
//并查集
for(int i=1;i<=m;i++){
int x,y;
read(x);read(y);
int kx=find(x),ky=find(y);
if(kx==ky)continue;
fa[kx]=ky;
}
//分组背包
for(int i=1;i<=n;i++){
int x=find(i);
if(!vis[x]){
for(int j=1;j<=w;j++)g[j]=f[j];//0个
int sa,sb;
sa=sb=0;
for(int j=1;j<=n;j++){
if(find(j)==x){//选一个
sa+=a[j];
sb+=b[j];
for(int k=w;k>=a[j];k--){
g[k]=max(g[k],f[k-a[j]]+b[j]);
}
}
}
for(int k=w;k>=sa;k--){//全选
g[k]=max(g[k],f[k-sa]+sb);
}
for(int i=1;i<=w;i++)f[i]=g[i];
vis[x]=1;
}
}
int ans=0;
for(int i=0;i<=w;i++)ans=max(ans,f[i]);
cout<<ans;
return 0;
}