中文题目 题目直接复制了:
题目描述
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
本题思路 首先每个云彩都有 W 和 V 其次云彩想要购买是整套购买的 那么问题来了,如果暂且先不去看 整套购买这个问题,这道题不就是个简单的背包吗 但是整套购买并不妨碍什么,一个并查集可以解决,但是注意 在构造unite 函数的时候 不妨把整个并查集里的 w 和 v 都加起来 构造成一个 “大物品” 来进行背包操作 很有意思的一道题
以下为AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct node
{
int price, val;
}a[10010];
int pre[10010], dp[10010];
int findx(int x)
{
return pre[x] == x ? x : findx(pre[x]);
}
void unite(int x,int y)
{
x = findx(x);
y = findx(y);
pre[x] = y;
a[y].price += a[x].price;
a[y].val += a[x].val;
}
int n, m, w;
void init()
{
for(int i = 1; i <= n; i ++)
{
pre[i] = i;
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&w))
{
for(int i = 1; i <= n; i ++)
scanf("%d%d",&a[i].price,&a[i].val);
init();
int u, v;
for(int i = 1; i <= m; i ++)
{
scanf("%d%d",&u,&v);
unite(u,v);
}
memset(dp,0,sizeof(dp));
for(int i = 1; i <= n; i ++)
if(pre[i] == i)
{
for(int j = w; j >= a[i].price; j --)
dp[j] = max(dp[j],dp[j-a[i].price] + a[i].val);
}
printf("%d\n",dp[w]);
}
return 0;
}