1. 程式人生 > >搭配購買(並查集+0/1揹包)

搭配購買(並查集+0/1揹包)

Joe覺得雲朵很美,決定去山上的商店買一些雲朵。商店裡有n朵雲,雲朵被編號為1,2,…,n,並且每朵雲都有一個價值。但是商店老闆跟他說,一些雲朵要搭配來買才好,所以買一朵雲則與這朵雲有搭配的雲都要買。但是Joe的錢有限,所以他希望買的價值越多越好。 輸入 第1行n(<=10000)、m(>=5000)、w(<=10000),表示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

並查集直接維護就好了

每次merge的時候把花費和價值也疊加給那一個

最後把所有自己是自己father的拿出來做一個0/1揹包就好了

結果一維陣列忘了價值要倒序列舉

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0;
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return
res; } int n,m,we,fa[10005],w[10005],c[10005],dp[10005]; inline int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } inline void merge(int x,int y){ int f1=find(x),f2=find(y); if(f1!=f2)fa[f1]=f2,c[f2]+=c[f1],w[f2]+=w[f1]; } int main(){ n=read(),m=read(),we=read(); for(int i=1;i<=n;i++) fa[
i]=i; for(int i=1;i<=n;i++){ c[i]=read(),w[i]=read(); } for(int i=1;i<=m;i++){ int u=read(),v=read(); merge(u,v); } for(int i=1;i<=n;i++){ if(fa[i]==i){ for(int j=we;j>=c[i];j--){ dp[j]=max(dp[j],dp[j-c[i]]+w[i]); } } } cout<<dp[we]<<'\n'; }