题目描述
Joe觉得云朵很美,决定去山上的商店买一些云朵。商店里有n朵云,云朵被编号为1,2,…,n,并且每朵云都有一个价值。但是商店老板跟他说,一些云朵要搭配来买才好,所以买一朵云则与这朵云有搭配的云都要买。但是Joe的钱有限,所以他希望买的价值越多越好。
输入
第1行n,m,w,表示n朵云,m个搭配,Joe有w的钱。
第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≤1,000;m≤100;w≤1,000;
100%的数据保证:n≤10,000;0≤m≤5000;w≤10,000。
代码
#include <bits/stdc++.h>
using namespace std;
int m,n,p;
int c[10010],d[10010],dp[10010],q[10010],v[10010],w[10010],num;
int find(int o)//并查集
{
if(q[o]==o)//是根节点
{
return o;
}
else
{
return q[o]=find(q[o]);//查找根节点并赋值
}
}
void merge(int i,int j)
{
int x=find(i);
int y=find(j);
if(x!=y)//不在一个集合
{
q[x]=y;//从右向左合并(作者的习惯,也可一从左向右)
c[y]+=c[x];
d[y]+=d[x];
}
}
int main()
{
cin>>n>>m>>p;
for(int i=1;i<=n;i++)
{
cin>>c[i]>>d[i];
}
for(int i=1;i<=n;i++)
{
q[i]=i;//并查集初始化
}
for(int i=1;i<=m;i++)
{
int k,b;
cin>>k>>b;
merge(k,b);//合并集合
}
for(int i=1;i<=n;i++)
{
if(q[i]==i)//只查根节点
{
num++;
v[num]=d[i];
w[num]=c[i];
}
}
for(int i=1;i<=num;i++)//背包
{
for(int j=p;j>=w[i];j--)
{
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[p];
return 0;
}
运行
并查集与背包会单独做一期!!!