[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;
}
posted @ 2023-08-18 15:43  inlinexhx  阅读(12)  评论(0编辑  收藏  举报