国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

回溯算法--01背包問題

這篇具有很好參考價值的文章主要介紹了回溯算法--01背包問題。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

回溯算法--01背包問題

[算法描述]

[回溯法基本思想]

法一:

法二:?

代碼:

?運行結(jié)果

代碼改進?


回溯算法--01背包問題

[算法描述]

0-1背包問題是子集選取問題。一般情況下,0-1背包問題是NP完全問題。0-1背包問題的解空間可以用子集樹表示。解0-1背包問題的回溯法與解裝載問題的回溯法十分相似。在搜索解空間樹時,只要其左兒子節(jié)點是一個可行的節(jié)點,搜索就進入其左子樹;而當(dāng)右子樹中有可能包含最優(yōu)解時才進入右子樹搜索,否則將右子樹剪去。設(shè)r是當(dāng)前剩余物品價值總和;cp是當(dāng)前價值;bestp是當(dāng)前最優(yōu)價值。當(dāng)cp+r<=bestp時,可剪去右子樹。計算右子樹中解的上界的更好的辦法是,將剩余物品依其單位重量價值排序,然后依次裝入物品,直至裝不下時,再裝入該物品的一部分而裝滿背包,由此得到的價值是右子樹的上界。

0--1背包的一個實例:

n=3, c=50,

w={10,30,20},

v(p)={60,120,100}的

0-1背包問題的最優(yōu)解和最優(yōu)值。<w為重量,v為價值量,n為物品個數(shù),c為背包容量>
?

[回溯法基本思想]

確定了解空間的組織結(jié)構(gòu)后,【回溯法從開始節(jié)點(根節(jié)點)出發(fā),以深度優(yōu)先搜索整個解空間。這個開始的節(jié)點為活節(jié)點,同時成為當(dāng)前的擴展節(jié)點。在當(dāng)前的擴展節(jié)點處,搜素向縱深方向移至一個新節(jié)點。這個新節(jié)點就成為新的活節(jié)點,并成為當(dāng)前擴展節(jié)點。如果當(dāng)前節(jié)點處不能再向縱深方向移動,則當(dāng)前擴展節(jié)點為死節(jié)點。此時,應(yīng)往回移動到最近的一個活節(jié)點處?;厮莘ㄒ赃@種方式遞歸的在解空間中搜素,直至找到所有符合要求的解或解空間中已無活節(jié)點?!浚瓷疃葍?yōu)先搜索)

【優(yōu)化方法】

剪枝(一):當(dāng)前決策放入的物品總重量已經(jīng)大于背包容量時,沒有必要繼續(xù)決策,此時可以將其左子樹剪掉。

剪枝(二):如果將當(dāng)前擴展節(jié)點后剩下的所有物品都裝入還沒有目前已求得的最優(yōu)值大的話,就不在進行決策了,直接返回。

遞歸回溯時,在當(dāng)前擴展節(jié)點處會通過設(shè)置約束函數(shù)和限界函數(shù)。不滿足條件的,剪去相應(yīng)的子樹

【0-1背包算法分析】

對于0-1背包問題,可用一顆完全二叉樹表示其解空間,針對上述實例(n=5),解空間樹有32個可能的解,解空間樹如下圖所示。

回溯算法--01背包問題

法一:

回溯算法是一種解決問題的通用算法,能夠在一個問題的所有解空間中,按深度優(yōu)先的策略搜索,直到找到所需要的解或者搜索完整個解空間都沒有找到解。0-1背包問題是指在限制背包容量的情況下,在一堆物品中選擇一部分,使得這些物品的總價值最大。

C++ 設(shè)計回溯算法解決 0-1 背包問題的思路如下:

  1. 定義一個全局?jǐn)?shù)組 max_value,用于存儲當(dāng)前找到的最大總價值;
  2. 定義一個局部數(shù)組 current_weight,用于存儲當(dāng)前已選物品的總重量;
  3. 定義一個遞歸函數(shù) backpack,用于搜索某一層的所有可能性;
  4. 在 backpack 函數(shù)中,首先判斷是否已經(jīng)遍歷完所有物品,如果是則更新數(shù)組 max_value;
  5. 如果還沒有處理完所有物品,則需要對當(dāng)前物品進行判斷。如果當(dāng)前物品的重量加上當(dāng)前已選物品的總重量仍然小于等于背包容量,則將當(dāng)前物品加入已選物品中,并進入下一層搜索。否則,不加入當(dāng)前物品,并進入下一層搜索。
  6. 在遞歸返回后,需要將當(dāng)前物品從已選物品中刪除,以方便下一次搜索。

一個簡單的 C++ 回溯算法解決 0-1 背包問題的示例代碼如下:

/*
* 回溯算法---0-1背包問題
*/
#include <iostream>
using namespace std;

const int max_n = 10;
const int capacity = 50;

int w[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };  // 物品重量數(shù)組
int v[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };  // 物品價值數(shù)組
bool selected[max_n]; // 記錄物品是否被選擇
int current_weight = 0;  // 當(dāng)前已選物品的總重量
int max_value = 0; // 已找到的最大總價值

// backpack 函數(shù)用于搜索某一層的所有可能性
void backpack(int i) {
    if (i == max_n) {  // 如果已經(jīng)遍歷完所有物品,則更新 max_value
        if (current_weight <= capacity && max_value < v[i]) {
            max_value = v[i];
        }
        return;
    }

    if (current_weight + w[i] <= capacity) {  // 如果能將當(dāng)前物品加入背包
        selected[i] = true;
        current_weight += w[i];
        backpack(i + 1);  // 進入下一層
        current_weight -= w[i];  // 遞歸返回后,需要將當(dāng)前物品從已選物品中刪除
        selected[i] = false;
    }

    backpack(i + 1);  // 進入下一層
}

int main() {
    backpack(0);  // 從第一個物品開始搜索
    cout << "最大總價值為:" << max_value << endl;
    return 0;
}

法二:?

代碼:

頭文件:

#pragma once
#include<iostream>
#include<cmath>
#include<vector>
#include < algorithm>
using namespace std;

源文件:

/*
* 回溯算法--01背包
*/
#include"01背包頭文件.h"

const int NUM = 50;
int c;		//背包容納的重量
int n;		//物品數(shù)量
int cw;		//當(dāng)前重量
int cv;		//當(dāng)前價值
int bestv;	//當(dāng)前最優(yōu)價值

//描述每個物品的數(shù)據(jù)結(jié)構(gòu)
struct Object {
	int w;		//物品的重量
	int v;		//物品的價值
	double d;	//物品的單位價值重量比(d=v/w)
}Q[NUM];		//物品的數(shù)組

bool cmp(Object a,Object b) {
	if (a.d>b.d){
		return true;
	}
	else{
		return false;
	}
}
//限界函數(shù)Bound()的實現(xiàn)
//形參i是回溯的深度
int Bound(int i) {
	int cleft = c - cw;  // 背包剩余容納的重量
	double b = cv;       // 上界價值

	while (i < n && Q[i].w <= cleft) {  // 盡量裝滿背包
		cleft -= Q[i].w;
		b += Q[i].v;
		i++;
	}

	if (i < n) {  // 剩余空間不足以容納物品 i 時,將物品 i 分配到背包中,直到背包裝滿
		b += 1.0 * Q[i].v / Q[i].w * cleft;
	}
	return b;
}

//形參i是回溯的深度,從0開始
void backtrack(int i){
	if (i + 1 > n) {
		bestv = cv;
		return;
	}
	//進入左子樹搜索
	if(cw+Q[i].w<=c) {
		cw = cw + Q[i].w;
		cv = cv + Q[i].v;
		backtrack(i + 1);
		cw = cw - Q[i].w;
		cv = cv - Q[i].v;
	}
	//進入右子樹搜索
	if(Bound(i+1)>bestv){
		backtrack(i + 1);
	}
}

int main() {
	cin >> c >> n;							//輸入背包容納的重量和物品數(shù)量
	for (int i = 0; i < n; i++) {
		cin >> Q[i].w >> Q[i].v;			//輸入物品的重量和物品的價值
		Q[i].d = 1.0 * Q[i].v / Q[i].w;		//物品的單位價值重量比(d=v/w)
	}				

	//排序
	sort(Q, Q + n, cmp);
	backtrack(0);
	cout << "最大總價值為:" << bestv << endl;   
	return 0;			
}

?運行結(jié)果

回溯算法--01背包問題

代碼改進?

上面的代碼已經(jīng)實現(xiàn)了 01 背包問題的求解,但是還有一些需要改進的地方,以下是我的建議:

  1. 你在回溯函數(shù) backtrack 中使用遞歸的方式進行搜索。雖然遞歸可以使得代碼更加簡潔,但是如果物品數(shù)量較大時,可能會導(dǎo)致棧溢出的問題。因此,建議采用迭代的方式進行搜索,使用一個棧來存儲搜索狀態(tài)。

  2. 在你的排序函數(shù)中,其實不必寫成一個 bool 類型的函數(shù),直接寫成一個比較函數(shù)即可。例如:

bool cmp(Object a, Object b) {
    return a.d > b.d;
}

3.你在計算排序后的上界時,可能會出現(xiàn)除數(shù)為 0 的情況(當(dāng)背包容量為 0 時)。因此,在計算物品的單位價值時,可以加上一個特判,例如:

if (Q[i].w == 0) {
    Q[i].d = 0;
} else {
    Q[i].d = 1.0 * Q[i].v / Q[i].w;
}

4.下面是修改過的代碼:

/*
 * 01 背包問題求解,回溯法實現(xiàn)
 * 輸入格式:
 * 第一行包含背包容量 c 和物品數(shù)量 n,以空格分隔;
 * 接下來 n 行,每行包含一個物品的重量和價值,以空格分隔。
 * 輸出格式:
 * 最大總價值
 */

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 50;

struct Object {
    int w, v;  // 物品重量和價值
    double d;  // 單位價值
};

bool cmp(Object a, Object b) {
    return a.d > b.d;
}

int main() {
    int c, n;
    cin >> c >> n;
    vector<Object> items(n);
    for (int i = 0; i < n; i++) {
        cin >> items[i].w >> items[i].v;
        if (items[i].w == 0) {
            items[i].d = 0;
        } else {
            items[i].d = 1.0 * items[i].v / items[i].w;
        }
    }
    sort(items.begin(), items.end(), cmp);  // 按單位價值排序
    int bestv = 0;  // 當(dāng)前最優(yōu)解
    vector<int> path(n);  // 存儲當(dāng)前搜索路徑
    int i = 0;  // 當(dāng)前搜索的物品編號
    int cw = 0;  // 當(dāng)前背包中物品的總重量
    int cv = 0;  // 當(dāng)前背包中物品的總價值
    while (true) {
        if (i >= n) {  // 遍歷完了所有物品,回溯
            if (bestv < cv) {
                bestv = cv;
            }
            if (path.empty()) {
                break;  // 遍歷完了所有狀態(tài),退出
            }
            i = path.back();  // 取出上一個搜索的物品
            path.pop_back();
            cw -= items[i].w;
            cv -= items[i].v;
            i++;  // 進入右子樹搜索
        } else if (cw + items[i].w <= c) {  // 左子樹搜索
            path.push_back(i);
            cw += items[i].w;
            cv += items[i].v;
            i++;  // 進入左子樹搜索
        } else {  // 右子樹搜索
            double bound = cv + (c - cw) * items[i].d;  // 計算上界
            if (bound < bestv) {
                if (path.empty()) {
                    break;  // 遍歷完了所有狀態(tài),退出
                }
                i = path.back();  // 取出上一個搜索的物品
                path.pop_back();
                cw -= items[i].w;
                cv -= items[i].v;
                i++;  // 進入右子樹搜索
            } else {
                i++;  // 進入左子樹搜索
            }
        }
    }
    cout << bestv << endl;
    return 0;
}

這段代碼實現(xiàn)了 01 背包問題的回溯算法求解,并且采用了剪枝策略進行優(yōu)化,基本思路如下:

  1. 首先,讀入背包容量 c 和物品數(shù)量 n,以及每個物品的重量和價值。

  2. 將物品按單位價值從大到小排序,這里采用了 C++ STL 中的 sort 函數(shù)。

  3. 從第一個物品開始進行搜索,使用一個棧來保存搜索路徑,路徑上的每個節(jié)點包含當(dāng)前已選中的物品編號、當(dāng)前背包中已裝載的物品總重量和總價值。

  4. 在搜索過程中,對于每個節(jié)點,分別考慮進入其左子樹和右子樹兩種情況。左子樹表示當(dāng)前物品被選擇放入背包,進入左子樹后要將物品的重量和價值加入到當(dāng)前背包中,并更新搜索路徑;右子樹表示當(dāng)前物品不放入背包,進入右子樹后只需要更新搜索路徑即可。

  5. 在進入下一個節(jié)點之前,使用剪枝策略計算這個節(jié)點的上界。這里使用了線性松弛法(Linear Relaxation),即假設(shè)當(dāng)前物品可以部分裝入背包中,按單位價值從大到小的順序裝入物品直到背包裝滿,則此時背包中物品的總價值加上剩余空間能夠容納的物品的單位價值乘以其重量即為當(dāng)前節(jié)點的上界。如果計算出來的上界小于當(dāng)前已知的最優(yōu)解,則可以剪枝,放棄進入左子樹的搜索,直接進入右子樹。因為進入左子樹的搜索必然不會得到更優(yōu)的解。

  6. 當(dāng)遍歷完所有節(jié)點后,輸出當(dāng)前的最優(yōu)解即可。

總體而言,這段代碼實現(xiàn)了一個簡潔高效的 01 背包問題求解算法。

?文章來源地址http://www.zghlxwxcb.cn/news/detail-405524.html

到了這里,關(guān)于回溯算法--01背包問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 湘潭大學(xué) 算法設(shè)計與分析實驗 回溯 動態(tài)規(guī)劃 貪心 模擬退火解決背包問題

    https://download.csdn.net/download/SQ_ZengYX/88620871 測試用例

    2024年02月02日
    瀏覽(42)
  • 算法系列--動態(tài)規(guī)劃--背包問題(1)--01背包介紹

    算法系列--動態(tài)規(guī)劃--背包問題(1)--01背包介紹

    ??\\\"趁著年輕,做一些比較cool的事情\\\"?? 作者:Lvzi 文章主要內(nèi)容:算法系列–動態(tài)規(guī)劃–背包問題(1)–01背包介紹 大家好,今天為大家?guī)淼氖?算法系列--動態(tài)規(guī)劃--背包問題(1)--01背包介紹 背包問題是動態(tài)規(guī)劃中經(jīng)典的一類問題,經(jīng)常在筆試面試中出現(xiàn),是非常 具有區(qū)分度 的題

    2024年04月16日
    瀏覽(93)
  • 算法設(shè)計 - 01背包問題

    算法設(shè)計 - 01背包問題

    學(xué)習(xí)來源 【自制】01背包問題算法動畫講解_嗶哩嗶哩_bilibili 問題描述 有N件物品,第i件物品的重量是w[i],價值是p[i]。 有一個背包,背包的承重是W。 求解:將哪些物品裝入背包可獲得最大價值。 實例說明 有如下物品,給定每件物品的重量和價值: 物品 重量 價值 葡萄 2

    2023年04月08日
    瀏覽(21)
  • 算法訓(xùn)練第四十二天|01背包問題 二維 、01背包問題 一維、416. 分割等和子集

    算法訓(xùn)練第四十二天|01背包問題 二維 、01背包問題 一維、416. 分割等和子集

    視頻鏈接:https://www.bilibili.com/video/BV1cg411g7Y6/ 參考:https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-1.html 對于面試的話,其實掌握01背包,和完全背包,就夠用了,最多可以再來一個多重背包。 而完全背包又是也是01背包稍作變化而來,即:完全

    2024年02月01日
    瀏覽(26)
  • 算法學(xué)習(xí)17-動態(tài)規(guī)劃01:背包問題

    算法學(xué)習(xí)17-動態(tài)規(guī)劃01:背包問題

    提示:以下是本篇文章正文內(nèi)容: 提示:這里對文章進行總結(jié): ??????

    2024年04月27日
    瀏覽(102)
  • 【算法5.1】背包問題 - 01背包 (至多最大價值、至少最小價值)

    【算法5.1】背包問題 - 01背包 (至多最大價值、至少最小價值)

    目錄 至少模板和至多模板的兩大區(qū)別 1、至多模板 2、至少模板 2. 01背包 - 至多模板?- 體積至多j,總價值最大 1、樸素做法?- 二維dp? 2、優(yōu)化 - 一維dp 4700. 何以包郵? -?至少模板?- 價值至少j,總價值最小 ? 初始化不同 : 至多模板求的是最大值,所以初始化為f[0~m]=0 至少模

    2024年02月12日
    瀏覽(18)
  • 算法套路十四——動態(tài)規(guī)劃之背包問題:01背包、完全背包及各種變形

    算法套路十四——動態(tài)規(guī)劃之背包問題:01背包、完全背包及各種變形

    如果對遞歸、記憶化搜索及動態(tài)規(guī)劃的概念與關(guān)系不太理解,可以前往閱讀算法套路十三——動態(tài)規(guī)劃DP入門 背包DP介紹:https://oi-wiki.org/dp/knapsack/ 0-1背包:有n個物品,第i個物品的體積為w[i],價值為v[i],每個物品至多選一個, 求體積和不超過capacity時的最大價值和,其中i從

    2024年02月10日
    瀏覽(89)
  • 【動態(tài)規(guī)劃】01背包問題——算法設(shè)計與分析

    【動態(tài)規(guī)劃】01背包問題——算法設(shè)計與分析

    若超市允許顧客使用一個體積大小為13的背包,選擇一件或多件商品帶走,則如何選擇可以使得收益最高? 商品 價格 體積 啤酒 24 10 汽水 2 3 餅干 9 4 面包 10 5 牛奶 9 4 0-1 Knapsack Problem 輸入: quad - n n n 個商品組成集合 O O O ,每個商品有屬性價格 p i p_i p i ? 和體積 v i v_i v

    2024年02月04日
    瀏覽(85)
  • 【算法日志】動態(tài)規(guī)劃刷題:01背包問題,多重背包問題(day37,day38)

    【算法日志】動態(tài)規(guī)劃刷題:01背包問題,多重背包問題(day37,day38)

    目錄 前言 目標(biāo)和(01背包) 一和零(01背包) 零錢兌換(多重背包) 排列總和(多重背包) 這兩天都是背包問題,其中的01背包的一些應(yīng)用問題需要一定的數(shù)學(xué)建模能力,需要i將實際問題簡化成我們熟悉的背包問題;而這兩天的多重背包問題還算比較基礎(chǔ),但也要我明白了

    2024年02月11日
    瀏覽(95)
  • 算法分析與設(shè)計——動態(tài)規(guī)劃求解01背包問題

    算法分析與設(shè)計——動態(tài)規(guī)劃求解01背包問題

    假設(shè)有四個物品,如下圖,背包總?cè)萘繛?,求背包裝入哪些物品時累計的價值最多。 我們使用動態(tài)規(guī)劃來解決這個問題,首先使用一個表格來模擬整個算法的過程。 表格中的信息表示 指定情況下能產(chǎn)生的最大價值 。例如, (4, 8)表示在背包容量為8的情況下,前四個物品的最

    2024年02月04日
    瀏覽(93)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包