题目链接 :http://codeforces.com/contest/742/problem/D
题意:给你n个女人的信息重量w和美丽度b,再给你m个关系,要求邀请的女人总重量不超过w
而且如果邀请了一个女人要么就邀请她一个,要么要邀请她还有她所有的朋友。
很明显是一道并查集+背包的问题,并不难。要注意的是背包的写法,由于选择情况有两种
1)只选一个女人
2)选和这个女人有关系的一群女人
于是背包最外层是关系数,即联通块的个数,次外层是背包大小,内层是联通个数(由于选择的要求在一个联通块中
只能选择一个或者全选所以背包大小要放在联通个数外面,毕竟只要选一次)然后就没然后了
#include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int M = 1010; const int inf = 0X3f3f3f3f; int wi[M] , be[M]; vector<int> vc , fr[M]; long long dp[M]; int temp , counts; int fa[M] , n , m , w; void init() { for(int i = 0 ; i <= n ; i++) { fa[i] = i; } } int getf(int x) { if(x != fa[x]) fa[x] = getf(fa[x]); return fa[x]; } void Union(int x , int y) { int xx = getf(x); int yy = getf(y); if(xx != yy) { fa[xx] = yy; } } void dfs(int pos) { for(int i = 1 ; i <= n ; i++) { int father = getf(i); if(father == pos) { fr[temp].push_back(i); } } } int main() { cin >> n >> m >> w; init(); for(int i = 1 ; i <= n ; i++) { cin >> wi[i]; } for(int i = 1 ; i <= n ; i++) { cin >> be[i]; } for(int i = 1 ; i <= m ; i++) { int x , y; cin >> x >> y; Union(x , y); } memset(dp , 0 , sizeof(dp)); temp = 0; for(int i = 1 ; i <= n ; i++) { if(fa[i] == i) { vc.push_back(i); } } int L = vc.size(); for(int i = 0 ; i < L ; i++) { temp++; dfs(vc[i]); } for(int i = 1 ; i <= temp ; i++) { int len = fr[i].size(); int sum1 = 0 , sum2 = 0; for(int j = 0 ; j < len ; j++) { int p = fr[i][j]; sum1 += wi[p]; sum2 += be[p]; } for(int l = M - 2 ; l >= 0 ; l--) { if(l + sum1 < M) { dp[l + sum1] = max(dp[l + sum1] , dp[l] + sum2); } for(int j = 0 ; j < len ; j++) { int p = fr[i][j]; if(l + wi[p] < M) { dp[l + wi[p]] = max(dp[l + wi[p]] , dp[l] + be[p]); } } } } long long MAX = 0; for(int i = 0 ; i <= w ; i++) { MAX = max(MAX , dp[i]); } cout << MAX << endl; return 0; }