题目链接 :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;
}