01背包dp+并查集 Codeforces Round #383 (Div. 2)

http://codeforces.com/contest/742/problem/D

题目大意:有n个人,每个人有重量wi和魅力值bi。然后又有m对朋友关系,朋友关系是传递的,如果a和b是朋友,b和c是朋友,那么a和c就是朋友。现在,把所有能作为朋友的人放在一个集合里面。你现在要开一个party,这个party的容量为W,现在,你每次只能选择一个集合里面的一个人或者选择集合里面的所有人进入这个party。在满足总w <= W的情况下,总魅力值b最大,问魅力值最大是多少?

思路:

定义dp(i, j)表示目前是第i个集合,party里面的重量为j的最大魅力值。

dp(i, j) = max(dp[i - 1][j], dp[i-1][j - 集合的总w(或集合的某个w)]) + 集合的总b(或集合中的某一个b)

 

复杂度O(n*n)

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 1000 + 5;
int dp[maxn][maxn];
vector<pair<int, int> > subset[maxn];
pair<int, int> f[maxn];
int par[maxn];
int n, m, w;

int pfind(int x){
    if (par[x] == x) return x;
    return par[x] = pfind(par[x]);
}

map<int, int> id;
int cnt = 0;
int get_id(int x){
    if (id.count(x) == 0) id[x] = ++cnt;
    return id[x];
}

int main(){
    cin >> n >> m >> w;
    for (int i = 1; i <= n; i++) par[i] = i;
    for (int i = 1; i <= n; i++)
        scanf("%d", &f[i].fi);
    for (int i = 1; i <= n; i++)
        scanf("%d", &f[i].se);
    for (int i = 1; i <= m; i++){
        int u, v; scanf("%d%d", &u, &v);
        int pu = pfind(u), pv = pfind(v);
        par[pv] = pu;
    }

    for (int i = 1; i <= n; i++){
        int myid = get_id(pfind(i));
        subset[myid].pb(f[i]);
    }

    for (int i = 1; i <= cnt; i++){
        for (int j = w; j >= 0; j--){
            int totw = 0, totb = 0;
            dp[i][j] = dp[i - 1][j];
            for (int k = 0; k < subset[i].size(); k++){
                pair<int, int> p = subset[i][k];
                totw += p.fi, totb += p.se;
                if (p.fi > j) continue;
                dp[i][j] = max(dp[i][j], dp[i - 1][j - p.fi] + p.se);
            }
            if (totw <= j){
                dp[i][j] = max(dp[i][j], dp[i - 1][j - totw] + totb);
            }
        }
    }

    int ans = 0;
    for (int i = 0; i <= w; i++)
        ans = max(ans, dp[cnt][i]);
    printf("%d\n", ans);
    return 0;
}
View Code

 

posted @ 2016-12-07 17:34  知る奇迹に  阅读(152)  评论(0编辑  收藏  举报