并查集训练-搭配购买(buy)

中文题目 题目直接复制了:

题目描述

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 
#include 
#include 
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;
}

 

你可能感兴趣的:(ACM,c++)