1. 程式人生 > >並查集訓練-搭配購買(buy)

並查集訓練-搭配購買(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 <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;
}