题目
https://www.luogu.com.cn/problem/P1455
思路:总体而言就是一个并查集加01背包问题,注意:我们在查找到父节点的时候,要将子节点的价值与重量全部放在父节点上,相当于将这一棵二叉树看作是一个大的物品,我们在打dp表的时候就就看父节点这个大的物品就可以了,而且我们在大dp表的时候不用用二维数组了
动态规划有一个后无效性原则:当前状态只于上一个有关,与上上一个无关
我们发现,在我们这个二维的dp表中,我们可以通过滚动数组的方式来进行压缩,
如果数据很大,需要的数组就很大,但是我们只需要上一个的最大价值就可以了
状态转移方程:
if(j>=w[i])
dp[j]=max(dp[j],dp[j-w[i]]+c[i])
也就是用一个一维数组就可以了
#include<bits/stdc++.h>
using namespace std;
int n,m,w;
#define maxn 10005
int dp[maxn];
int val[maxn],rmb[maxn],arr[maxn];
void init(){
for(int i=1;i<=n;i++)
arr[i]=i;
return ;
}
int getf(int u)
{
if(arr[u]==u)
return u;
else
arr[u]=getf(arr[u]);
return arr[u];
}
void merge(int x,int y)
{
int fx=getf(x);
int fy=getf(y);
if(fx!=fy)//注意要累加
{
arr[fx]=fy;
rmb[fy]+=rmb[fx];
val[fy]+=val[fx];
}
}
int main(){
int x,y;
cin>>n>>m>>w;
init();
for(int i=1;i<=n;i++)
cin>>rmb[i]>>val[i];
for(int i=0;i<m;i++)
{
cin>>x>>y;
merge(x,y);
}
for(int i=1;i<=n;i++)
{
if(arr[i]==i)
{
for(int j=w;j>=rmb[i];j--)
dp[j]=max(dp[j],dp[j-rmb[i]]+val[i]);
}
}
cout<<dp[w]<<endl;
}