• #383 Div1 Problem B Arpa's weak amphitheater.... (分组背包 && 并查集)


    题意 : 有n个人,每个人都有颜值bi与体重wi。剧场的容量为W。有m条关系,xi与yi表示xi和yi是好朋友,在一个小组。 每个小组要么全部参加舞会,要么参加人数不能超过1人。 问保证总重量不超过W,剧场中的颜值最大能到多少?

    分析 : 很显然的分组背包题目, 不过有所不同, 先来回顾一下普通的分组背包的描述 给出一个背包,背包有容量C,再给出N组物品,每组物品有ki种,每种物品有对应的体积Vi,价值Pi,每组物品至多选一种,且最多取一件。求用背包装物品,能获得的最大总价值是多少。可以发现和上面的不同之处就是多了一个可以全取的操作, 其实只要再在每一组里面加上所有的物品和就行了, 便成了一道普通的模板题了!在分组的时候使用简单的并查集即可!

    瞎搞 : 在实现的时候很慢, 还老是犯小错误, 归其原因就是分组背包接触太少, 即使是模板题也写的有点不流利!

    #include<bits/stdc++.h>
    using namespace std;
    struct st
    {
        int w, v, id;
    };
    st arr[1001];
    int v[1001][1001], w[1001][1001], dp[1001], p[1001];///p数组表示各个组里面的物品个数
    int sumv[1001], sumw[1001];
    int c[1001];
    map<int, int> M;
    int findset(int x)
    {
        int root = x;
        while(c[root] != root) root = c[root];
        int j;
        while(c[x] != root){
            j = c[x];
            c[x] = root;
            x = j;
        }
        return root;
    }
    inline int join(int a, int b)
    {
        int f = findset(a), ff = findset(b);
        if(f != ff){
            c[f] = ff;
        }
    }
    #define IN 0
    #define OUT 0
    int main(void)
    {
        #if IN
            freopen("in.txt", "r", stdin);
        #endif
        #if OUT
            freopen("out.txt", "w", stdout);
        #endif
        int n, m, C;
        scanf("%d%d%d", &n, &m, &C);
        M.clear();
        for(int i=0; i<=n; i++){
            memset(v[i], 0, sizeof(v[i]));
            memset(w[i], 0, sizeof(w[i]));
            memset(p, 0, sizeof(p));
            memset(dp, 0, sizeof(dp));
            memset(sumw, 0, sizeof(sumw));
            memset(sumv, 0, sizeof(sumv));
            arr[i].id = i;//忽略这个id, 没有用, 懒得改了.....
            c[i] = i;
        }
        for(int i=1; i<=n; i++) scanf("%d", &arr[i].w);
        for(int i=1; i<=n; i++) scanf("%d", &arr[i].v);
        for(int i=0; i<m; i++){
            int a, b;
            scanf("%d%d", &a, &b);
            join(a, b);
        }
        int top = 0;///表示组数
        bool vis[1001];
        memset(vis, true, sizeof(vis));
        for(int i=1; i<=n; i++){
            int temp = findset(i);
            if(vis[temp]){///如果还没有出现过这个在并查集里面的“大佬”
                M[temp] = top;//记录一下老大所在的组的下标元素
                vis[temp] = false;
                v[top][p[top]] = arr[i].v;
                w[top][p[top]] = arr[i].w;
                sumv[top] += arr[i].v;
                sumw[top] += arr[i].w;
                p[top]++, top++;
            }else{
                int Top = M[temp];
                v[Top][p[Top]] = arr[i].v;
                w[Top][p[Top]] = arr[i].w;
                sumv[Top] += arr[i].v;
                sumw[Top] += arr[i].w;
                p[Top]++;
            }
        }
        for(int i=0; i<top; i++){
            if(p[i]==1) continue;//这里需要注意, 只有一个元素的时候, 不应该再加所有元素的和, 会重复的!
            v[i][p[i]] = sumv[i];
            w[i][p[i]] = sumw[i];
            p[i]++;
        }
    ///Debug begin
    //    printf("top = %d
    ", top);
    //    for(int i=0; i<top; i++){
    //        printf("In group %d
    ", i);
    //        printf("v");puts("");
    //        for(int j=0; j<p[i]; j++){
    //            printf("ord=%d, v=%d
    ", j, v[i][j]);
    //        }
    //        printf("w");puts("");
    //        for(int j=0; j<p[i]; j++){
    //            printf("ord=%d, w=%d
    ", j, w[i][j]);
    //        }
    //        puts("");
    //    }
    //    puts("");
    ///Debug end
        for(int i=0; i<top; i++){
            for(int j=C; j>=0; j--){
                for(int k=0; k<p[i]; k++){
                    if(w[i][k] <= j)
                    dp[j] = max(dp[j], dp[j-w[i][k]]+v[i][k]);
                }
            }
    ///Debug begin
    //        for(int ii=1; ii<=C; ii++){
    //            printf("%d ", dp[ii]);
    //        }
    //        puts("");
    ///Debug end
        }
        printf("%d
    ", dp[C]);
        return 0;
    }
    View Code
  • 相关阅读:
    取消GridView/ListView item被点击时的效果 记录学习
    EditText 几种显示方式,固定行数,自适应行数
    Android 判断当前屏幕是横屏还是竖屏
    Android 用代码设置Shape,corners,Gradient
    Android 横屏不让输入法全屏显示
    js-JavaScript高级程序设计学习笔记7
    js-FCC算法-Pairwise
    js-JavaScript高级程序设计学习笔记6
    js-JavaScript高级程序设计学习笔记5
    js-自制轮播插件!
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/6926339.html
Copyright © 2020-2023  润新知