搭配购买

题目穿越门
题目描述
明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有n朵云,云朵已经被老板编号为1,2,3,……,n,并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉得这礼物实在是太新奇了,但是你的钱是有限的,所以你肯定是想用现有的钱买到尽量多价值的云。

输入格式
第1行n,m,w,表示n朵云,m个搭配和你现有的钱的数目

第2行至n+1行,每行ci,di表示i朵云的价钱和价值

第n+2至n+1+m ,每行ui,vi表示买ui就必须买vi,同理,如果买vi就必须买ui

输出格式
一行,表示可以获得的最大价值

输入输出样例
输入
5 3 10
3 10
3 10
3 10
5 100
10 1
1 3
3 2
4 2

输出
1
说明/提示
30%的数据满足:n<=100

50%的数据满足:n<=1000;m<=100;w<=1000;

100%的数据满足:n<=10000;0<=m<=5000;w<=10000.

正解
这道题正解就是并查集+01背包
下面是思路:
答案很明显是可以的。可以利用并查集,将这m组配对购买的商品划到一个集合里,这样就可以确定买了其中一个就得买另一个。
最后就是01背包啦!

并查集

AC代码

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,w,u,v,c[10005],d[10005],f[10005],pre[10005];
int find(int x)//找爸爸+压缩路径
{
   
	if(pre[x]==0)return x;
	return pre[x]=find(pre[x]);
}
void bcj(int x,int y)//并查集
{
   
	int x1=find(x),y1=find(y);//先找爸爸
	if(x1!=y1)//不一样就合并
	{
   
		pre[y1]=x1;//合并
		c[x1]+=c[y1];//累加
		d[x1]+=d[y1];
		c[y1]=0;//记得清零(不然会干扰到01背包)
		d[y1]=0;
	}
}
int main()
{
   
	cin>>n>>m>>w;
	for(int i=1;i<=n;i++)
	 cin>>c[i]>>d[i];
	for(int i=1;i<=m;i++) 
	{
   
		cin>>u>>v;
		bcj(u,v);//并查集
	}
	for(int i=1;i<=n;i++)//01背包,年轻人都会
	 if(c[i]!=0)
	  for(int j=w;j>=c[i];j--)
	   f[j]=max(f[j],f[j-c[i]]+d[i]);
	cout<<f[w];   
	return 0;
}

谢谢观看