[LSGDOJ 1299]搭配买卖(并查集+01背包)
tnnd考试里做出来了结果merge
函数写错了,血压蹭蹭涨
题意
给\(n\)个数的重量价值\(c_i\)和\(d_i\)
现在选一些数(设选了\(k\)个数),使得\(\sum_\limits{i=1}^k c_i \le w\)且$\sum_\limits{i=1}^k d_i $最大
并且给\(m\)组关系\(x,y\),表示如果选\(x\)则需要选\(y\),选\(y\)同理
思路
看题就很像背包...
先并查集合并需要一起买的,再把一个集当作物品,然后价值重量就是集中元素之和
然后套\(01\)背包板子就行了
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int fa[N];//祖先
int w[N],v[N];//重量,价值
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
if(find(fa[x])!=find(fa[y])) fa[find(x)]=find(y);
}
int n,m,c;//n朵云,m搭配,现有的钱
int x,y;
int nw[N],nv[N];//并查集之后集的数量,每个集总共的重量和价值
int dp[N];
int main()
{
//freopen("buy.in","r",stdin);
//freopen("buy.out","w",stdout);
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=N;i++) fa[i]=i;
for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&v[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
merge(x,y);
}
for(int i=1;i<=n;i++)
{
int u=find(i);
nw[u]+=w[i];
nv[u]+=v[i];
}
// for(int i=1;i<=n;i++) if(fa[i]==i) cout<<nw[i]<<" "<<nv[i]<<endl;
for(int i=1;i<=n;i++)
{
for(int j=c;j>=nw[i];j--)
{
dp[j]=max(dp[j],dp[j-nw[i]]+nv[i]);
}
}
cout<<dp[c];
return 0;
}