分析

分组背包加并查集。

本题的并查集是最基本的满足传递性的朋友关系,所以直接合并即可。

然后用背包分组别进行运算,\(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;
}



posted on 2021-11-12 16:17  漠寒·  阅读(47)  评论(0)    收藏  举报