首页 > 其他分享 >01背包问题的子集树搜索

01背包问题的子集树搜索

时间:2023-10-16 23:23:18浏览次数:40  
标签:01 qw int vi wi qi 背包 子集 push

如题:

 

经典01背包问题,直接代码反映心路历程。

//
// Created by _thinkPad on 2023/10/16.
//
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>

using namespace std;

/*
 * 第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
 * 接下来有 N行,每行两个整数 vi,wi,用空格隔开
 * 分别表示第 i 件物品的体积和价值。
 */

// 尝试一下bfs,十分滴粗糙
void s0() {
    int N, V;
    cin >> N >> V;
    vector<int> v, w;
    for (int i = 0; i < N; i++) {
        int t1, t2;
        cin >> t1 >> t2;
        v.push_back(t1);
        w.push_back(t2);
    }
    int i = 0;
    queue<int> qt;
    queue<pair<int, int>> qvw;
    qt.push(i);
    qvw.emplace(V, 0);
    int res = 0;
    while (!qt.empty()) {
        i = qt.front();
        pair<int, int> tvw = qvw.front();
        qvw.pop();
        qt.pop();
        if (tvw.second >= res)
            res = tvw.second;
        if (i == N)
            continue;
        if (tvw.first >= v[i]) {
            qt.push(i + 1);
            qvw.emplace(tvw.first - v[i], tvw.second + w[i]);
        }
        qt.push(i + 1);
        qvw.emplace(tvw.first, tvw.second);

    }
    cout << res << endl;

}

// 暴力bfs超时,进行剪枝优化一下,使用一个sum对未来最大进行预判
void s1() {
    int N, V;
    cin >> N >> V;
    vector<int> v, w, sum;
    for (int i = 0; i < N; i++) {
        int t1, t2;
        cin >> t1 >> t2;
        v.push_back(t1);
        w.push_back(t2);
        sum.push_back(t2);
    }
    for (int i = N - 2; i >= 0; i--) {
        sum[i] += sum[i + 1];
    }
    int i = 0, vi = V, wi = 0, sumi = sum[0];
    queue<int> qi, qv, qw, qsum;
    qi.push(i);
    qv.push(vi);
    qw.push(wi);
    qsum.push(sumi);


    int res = 0;
    while (!qi.empty()) {
        i = qi.front(), vi = qv.front(), wi = qw.front(), sumi = qsum.front();
        qi.pop(), qv.pop(), qw.pop(), qsum.pop();
        if (wi >= res)
            res = wi;
        if (res >= sumi + wi)
            continue;
        if (i == N)
            continue;
        if (vi >= v[i]) {
            qi.push(i + 1);
            qv.push(vi - v[i]);
            qw.push(wi + w[i]);
            qsum.push(sum[i + 1]);
        }
        qi.push(i + 1);
        qv.push(vi);
        qw.push(wi);
        qsum.push(sum[i + 1]);

    }
    cout << res << endl;

}

// 使用限界函数还是失败了(优化了200ms),水一个dfs(就是把queue换stack哈哈哈哈哈)
void s2() {
    int N, V;
    cin >> N >> V;
    vector<int> v, w, sum;
    for (int i = 0; i < N; i++) {
        int t1, t2;
        cin >> t1 >> t2;
        v.push_back(t1);
        w.push_back(t2);
        sum.push_back(t2);
    }
    for (int i = N - 2; i >= 0; i--) {
        sum[i] += sum[i + 1];
    }
    int i = 0, vi = V, wi = 0, sumi = sum[0];
    stack<int> qi, qv, qw, qsum;
    qi.push(i);
    qv.push(vi);
    qw.push(wi);
    qsum.push(sumi);


    int res = 0;
    while (!qi.empty()) {
        i = qi.top(), vi = qv.top(), wi = qw.top(), sumi = qsum.top();
        qi.pop(), qv.pop(), qw.pop(), qsum.pop();
        if (wi >= res)
            res = wi;
        if (res >= sumi + wi)
            continue;
        if (i == N)
            continue;
        if (vi >= v[i]) {
            qi.push(i + 1);
            qv.push(vi - v[i]);
            qw.push(wi + w[i]);
            qsum.push(sum[i + 1]);
        }
        qi.push(i + 1);
        qv.push(vi);
        qw.push(wi);
        qsum.push(sum[i + 1]);

    }
    cout << res << endl;
}

// dfs很显然也是不行的,本质上和bfs差不多,整一个优先队列试试
// 就是按照可以分割物品进行横刀阔斧的剪枝
// 不过优先队列剪枝过程太麻烦了,还需要排序
// 为了方便定义一个类记录状态和排序
class bestQu {
public:
    int v, w;
    float preW;

    explicit bestQu(int vv = 0, int ww = 0) {
        v = vv, w = ww;
        preW = (float) ww / vv;
    }

    bool operator>(bestQu c) const {
        return (double(w) / v) > (double(c.w) / c.v);
    }

    bool operator<(bestQu c) const {
        return (double(w) / v) < (double(c.w) / c.v);
    }

    bool operator==(bestQu c) const {
        return (w == c.w && v == c.v);
    }

    void print() {
        cout << "体积: " << v << " 价值: " << w << " 单位体积价值: " << preW << endl;
    }

    static inline void getBestP(int &bestp, const vector<bestQu> &VW, int V, int i) {
        bestp = 0;
        for (int j = i; j < VW.size(); j++) {
            if (V > 0) {
                if (V >= VW[i].v) {
                    V -= VW[i].v;
                    bestp += VW[i].w;
                } else {
                    // bestp += (int) VW[i].preW * V;
                    bestp += (int) (VW[i].preW * V);// 这里这个(int)强制转换一定要把后面括起来,要不然边界会出问题
                    V = 0;
                }

            } else {
                break;
            }
        }
    }

};


void s3() {
    int N, V;
    cin >> N >> V;
    vector<bestQu> VW;
    int bestp;
    for (int i = 0; i < N; i++) {
        int t1, t2;
        cin >> t1 >> t2;
        VW.emplace_back(t1, t2);
    }
    sort(VW.rbegin(), VW.rend());
    bestQu::getBestP(bestp, VW, V, 0);

    int i = 0, vi = V, wi = 0;
    queue<int> qi, qv, qw;
    qi.push(i);
    qv.push(vi);
    qw.push(wi);


    int res = 0;
    while (!qi.empty()) {
        i = qi.front(), vi = qv.front(), wi = qw.front();
        bestQu::getBestP(bestp, VW, vi, i);
        qi.pop(), qv.pop(), qw.pop();
        if (wi >= res)
            res = wi;
        if (res >= bestp + wi)
            continue;
        if (i == N)
            continue;
        if (vi >= VW[i].v) {
            qi.push(i + 1);
            qv.push(vi - VW[i].v);
            qw.push(wi + VW[i].w);

        }
        qi.push(i + 1);
        qv.push(vi);
        qw.push(wi);


    }
    cout << res << endl;

}

// 经过不断的改良,搜索法过了

#ifndef test

int main() {
    s3();
    return 0;
}

#endif

s0:1900ms

s1:1700ms

s2:1700ms

s3:1ms

标签:01,qw,int,vi,wi,qi,背包,子集,push
From: https://www.cnblogs.com/duxingmengshou/p/17768679.html

相关文章

  • 生活随笔-20231016
        早起,叫醒小非,为他制作了”可颂滑蛋香肠沙拉“,自己准备的可颂未加香肠,非常美味,我俩都吃的津津有味。        小非上学后,按计划完成书本第三章思维导图第一节。    中午继续观看【大明王朝1566】-20~21集晚上下班到家,按计划带小齐来到楼下,让他练......
  • 每日总结20231016
    代码时间(包括上课)3h代码量(行):20行博客数量(篇):1篇相关事项:1、今天是周一,一周里面最容易犯困的一天,但是这次没有那么困,这次还算是学了不少的,今天上的是软件设计模式和人机交互技术。2、软件设计模式这次讲了三种模式,中介者模式、备忘录模式、观察者模式,人机交互技术讲的是盒子模......
  • 每日总结1016
    代码时间(包括上课)3h代码量(行):20行博客数量(篇):1篇相关事项:1、今天是周一,一周里面最容易犯困的一天,但是这次没有那么困,这次还算是学了不少的,今天上的是软件设计模式和人机交互技术。2、软件设计模式这次讲了三种模式,中介者模式、备忘录模式、观察者模式,人机交互技术讲的是盒子模......
  • pandas教程01: pandas的安装和基本操作
    pandas是Python中常用的数据处理库,主要用来处理表格数据,类似于下面这种:好好干文化有限公司员工薪资表姓名年龄性别年薪奖金久九刘35男18260042000傅儿待24男996000040000000舍处28女6000018000大家想一想,无论是日常办公使用的excel还是数据库,是......
  • 20231016-日记
    距离CSP还有5天上午-模拟赛总结T1-魔力子串考虑对于每个右端点找到它能匹配的状态,使用前缀和思想以方便统计.这里我们定义"状态"为前缀的各个字母的数量,减去最少得字母数量,经过化简,我们一定可以从前面相同的状态直接转移过来.因此可以开一个巨大的map,里面存的结......
  • [COCI2015-2016#4] ENDOR 题解
    [COCI2015-2016#4]ENDOR题解首先要发现一个很重要的性质,那就是两只变色龙碰撞后回头,等效于两只变色龙继续往前走,其中向右走的颜色不变,而向左走的要改变颜色。那这样就有一种\(O(n^2)\)的做法:对于向右的变色龙,直接贡献答案;对于向左的变色龙,我们按照碰到的先后顺序枚举它前面......
  • 20231016打卡
    上午的课程是铁道技术认知。在这门课上,我们学习了铁道的基础知识,包括受电弓、道岔变道器等。通过老师的讲解和课堂讨论,我们对铁道的运行和设备有了更深入的了解。在课程中,我们还通过虚拟仿真系统在计算机上学习了如何具体进行变轨操作和模拟动车组的运行。此外,通过沙盘的实际操作,......
  • [NOIP2010 提高组] 乌龟棋
    题目背景小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。题目描述乌龟棋的棋盘是一行NN个格子,每个格子上一个分数(非负整数)。棋盘第11格是唯一的起点,第NN格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。乌龟棋中MM张爬行卡片,分成44种不同的类型(MM张......
  • VA01/VA02/VA03 销售订单根据定价和步骤校验权限隐藏价格
    1、业务需求针对用户使用销售订单时,根据定价和步骤顺序,判断是否有权限,没有权限时隐藏销售订单抬头和行项目的部分价格数据要限制的定价和步骤在spro中的位置限制的步骤2、增强实现2.1权限对象创建带有定价和步骤的权限对象分配权限2.2、隐藏抬头和行项目价格隐藏抬头......
  • 设计模式01 —— 设计模式简介
    设计模式01——设计模式简介本教程参考:菜鸟教程-学的不仅是技术,更是梦想!(runoob.com)为本人学习笔记,和课程学习笔记,希望各位大佬多多指点!设计模式的简介设计模式可以看作一套被人反复使用的,多人知晓的代码设计的经验总结。设计模式是软件工程的基石。以下是完全版:设......