ACDREAM 05E 哗啦啦族的01背包问题(DFS专场)

本文探讨了一种解决复杂01背包问题的方法,通过折半搜索和深度优先搜索结合的方式,优化了求解过程,提高了效率。具体介绍了算法实现细节,包括变量定义、输入输出规范以及实例解析。

ACDREAM 05E 哗啦啦族的01背包问题

Problem Description

背包背包!

唐老师非常开心的在给小彭玉讲背包问题,“01背包就是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2……Wn,与之相对应的价值为P1,P2……Pn。求出获得最大价值的方案。”

在讲完这句话,唐老师就给小彭玉出了道01背包的课后习题,但是小彭玉不会做,那么就只能给你做了~

“有N个物品,你的背包空间为W,每个物品的体积和价值都是W1,W2……Wn。求最大能获得多大价值?”
Input

输入第一行有两个整数N,W。 1<=N<=40,0<=W<=100000000。

接下来一行有N个数,表示物品的体积和价值,W[i]<=100000000。
Output
输出一个整数,表示我们能够获得的最大价值。
Sample Input

4 10
4 3 5 11

Sample Output

9

题目大意:一个价值很大的01背包问题。
解题思路:其实并不是01背包问题。是DFS,但是要折半。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long ll;
int n, w, R, L;
int vis[50];
ll W[50], ans, aL[1<<20], aR[1<<20];
void DFS() {
    int pos;
    ll temp;
    int cnt1 = 0;
    for (int i = 0; i < (1<<L); i++) {
        temp = 0;
        for (int j = 0; j < L; j++) {
            if (i & (1 << j)) {
                temp += W[j];
            }
        }
        if (temp <= w) {
            aL[cnt1++] = temp;
//          printf("%lld ", aL[cnt1 - 1]);
        }
    }
//  puts("");
    int cnt2 = 0;
    for (int i = 0; i < (1 << R); i++) {
        temp = 0;
        for (int j = 0; j < R; j++) {
            if (i & (1 << j)) {
                temp += W[L + j];
            }
        }
        if (temp <= w) {
            aR[cnt2++] = temp;
//          printf("%lld ", aR[cnt2 - 1]);
        }
    }
    sort(aR, aR + cnt2);
    for (int i = 0; i < cnt1; i++) {
        if (aL[i] == w) {
            ans = w;
            return;
        }
        ll sub = w - aL[i];
        int rec = upper_bound(aR, aR + cnt2, sub) - aR - 1;
//      if (aL[i] == 7) printf("??%lld %lld!!!\n", sub, aR[rec]);
        if (aL[i] + aR[rec] > ans && aL[i] + aR[rec] <= w) {
            ans = aL[i] + aR[rec];
        }   
    }
}
int main() {
    while (scanf("%d %d", &n, &w) == 2) {
        memset(aL, 0, sizeof(aL));
        memset(aR, 0, sizeof(aR));
        ans = 0;
        ll temp = 0;
        for (int i = 0; i < n; i++) {
            scanf("%lld", &W[i]);
            temp += W[i];
        } 
        if (temp <= w) {
            printf("%lld\n", temp);
            continue;
        }
        L = n / 2;
        R = n - n / 2;
        DFS();
        printf("%lld\n", ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值