Codeforces Round #383 (Div. 2)D. Arpa's weak amphitheater and Mehrdad's valuable Hoses(dp背包+并查集)

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

posted @ 2016-12-07 13:56  Gealo  阅读(164)  评论(0编辑  收藏  举报