並查集訓練-搭配購買(buy)
阿新 • • 發佈:2018-11-11
中文題目 題目直接複製了:
題目描述
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; }