题意:原题在这
有n个人(1<=n<=1000)。每个人有一个重量wi(1<=wi<=1000)和一个魅力值bi(1<=bi<=10^6)。 n个人之间有m(1<=m<=min(n*(n-1)/2, 10^5))个关系。第i个关系由两个数字xi和yi组成,表示第xi个人和第yi个人是朋友,朋友关系是双向的。 已知若a和b是朋友,b和c是朋友,则a和c是朋友。 现在Mehrdad要邀请一些人来到派对,使这些人的重量总和不超过wi(1<=wi<=1000),且魅力值总和尽量大。同一个朋友圈里的人,只能邀请其中的一个人,或者全部人,或者一个人也不邀请。
输入格式: 第一行,三个整数n,m,w 第二行,n个整数w1,w2,...,wn 第三行,n个整数b1,b2,...,bn 接下来m行,每行表示一个关系,第i行有两个整数xi和yi。每一组朋友关系都是不同的。
输出格式: 一行,表示最大的魅力值总和。
做法:
1. 用并查集管理集合,开vector数组方便对集合进行遍历
2. 把集合看成一件物品,因为要么从集合中取一个元素,要么取整个集合,那么就对这个集合中的每件物品背一次,然后对这件物品背一次。
3.dp[i]表示当前重量为i的最大颜值,输出dp[maxweight]即可。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include<vector> #define inf 9999999999 using namespace std; int n,m,weight; vector<int> vec[1005]; int by[1005], wt[1005], fa[1005]; long long dp[1005]; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void unite(int x,int y) { fa[find(x)]=fa[find(y)]; } int main() { cin>>n>>m>>weight; for(int i=1;i<=n;i++) cin>>wt[i]; for(int i=1;i<=n;i++) cin>>by[i]; for(int i=1;i<=n;i++) fa[i]=i; for(int i=0;i<m;i++) { int x;int y; cin>>x>>y; if(find(x)!=find(y)) unite(x, y); } for(int i=1;i<=n;i++) vec[find(i)].push_back(i); for(int i=1;i<=n;i++) { if(fa[i]==i) { for(int j=weight;j>=0;j--) { int sumwt=0,sumby=0; for(int k=0;k<vec[i].size();k++) { sumby+=by[vec[i][k]]; sumwt+=wt[vec[i][k]]; if(j>=wt[vec[i][k]]) dp[j]=max(dp[j],dp[j-by[vec[i][k]]]+by[vec[i][k]]); } if(j>=sumwt) dp[j]=max(dp[j],dp[j-sumwt]+sumby); } } } cout<<dp[weight]<<endl; return 0; }