• 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
    ")
    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
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    MySQL视图更新
    JavaScript经典作用域问题
    进程间通信的几种方式
    Vue(MVVM)、React(MVVM)、Angular(MVC)对比
    CDN(Content Delivery Network)技术原理概要
    单点登录实现原理(SSO)
    composer 实现自动加载原理
    PHP 反射的简单使用
    php7安装php-redis扩展
    Git 简单入门(二)
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6142076.html
Copyright © 2020-2023  润新知