回溯法解01背包问题_01背包问题回溯法伪代码

回溯法解01背包问题_01背包问题回溯法伪代码一、问题n皇后问题的解空间树是一颗排列树,而01背包问题的解空间树应该是一颗子集树。再简述下该问题:有n件物品和一个容量为c的背包。第i件物品的价值是v[i],重量是w[i]。求解将哪些物品装入背包可使价值总和最大。所谓01背包,表示每一个物品看成一个整体,要么全部装入,要么都不装入。这里n=5,c=10,w={2,2,6,5,4},v={6,3,5,4,6}。01背…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

一、问题

n皇后问题的解空间树是一颗排列树,而01背包问题的解空间树应该是一颗子集树。再简述下该问题:有n件物品和一个容量为c的背包。第i件物品的价值是v[i],重量是w[i]。求解将哪些物品装入背包可使价值总和最大。所谓01背包,表示每一个物品看成一个整体,要么全部装入,要么都不装入。这里n=5, c=10, w={2, 2, 6, 5, 4}, v={6, 3, 5, 4, 6}。

01背包属于找最优解问题,用回溯法需要构造解的子集树。在搜索状态空间树时,只要左子结点是可一个可行结点,搜索就进入其左子树。对于右子树时,先计算上界函数,以判断是否将其剪枝。为了更好地计算和运用上界函数剪枝,可以先将物品按照其单位重量价值从大到小排序,此后就按照顺序考虑各个物品。

剪枝的两种情况:

①左结点深度搜索的条件是当前物品装得下,即cw+w[i]<=c

②将当前剩余所有物品都装入背包,获得的总价值也没能大于当前已经求得的最大价值bestp时

二、c++代码

#include <iostream>
#include <cmath>
using namespace std;


int n;//物品数量
double c;//背包容量
double v[100];//各个物品的价值
double w[100];//各个物品的重量
double cw = 0.0;//当前背包重量
double cp = 0.0;//当前背包中物品价值
double bestp = 0.0;//当前最优价值
double perp[100];//物品按单位重量价值排序后
int x[100];//是否装入,为0或1 
int best[100];//记录最优解,为0或1 
double v2[100];//临时存放各个物品的价值
double w2[100];//临时存放各个物品的重量


//交换两元素 
void swap(int i,int j,double arr[]){
     double t;
     t=arr[i];arr[i]=arr[j];arr[j]=t;                
     }
 
//快速排序算法 
void quicksort(int p,int q,double arr[],double key){
    int i,j;
    i=p;
    j=q;
    if(p>=q){
         return;
         }
    
    while(1){
            while(j>=p && arr[j]<key){j--;}
            if(j<=i) 
            break;
            swap(i,j,arr);
            swap(i,j,w2);
            swap(i,j,v2);

            
            while(i<=q && arr[i]>=key){i++;}                                  
            if(j<=i) 
            break;
            swap(i,j,arr);
            swap(i,j,w2);
            swap(i,j,v2);
          
            
            }
            
     quicksort(p,j-1,arr,arr[p]);
     quicksort(j+1,q,arr,arr[j+1]);   
    
    }

//按单位价值排序
void knapsack(int t)
{       
   quicksort(t,n,perp,perp[t]);    
}

//回溯函数
//每个结点的左右子树都要判断,因为装或不装两种情况都要考虑 
void backtrack(int i)
{
    double bound(int i);
   
    if(i>n)//到达叶结点,得出一个解 
    {
    bestp = cp;
    for(int k=1;k<=n;k++)
    {      
       best[k]=x[k];//把最优解记录下来      
    }
       return;
    }
    
    if(cw+w[i]<=c)//搜索左子树 
    {
       cw+=w[i];
       cp+=v[i];
       x[i]=1;
       backtrack(i+1);
       cw-=w[i];
       cp-=v[i];
       x[i]=0;
    }   
    
   if(bound(i+1)>bestp)//搜索右子树,必要时剪枝 
       backtrack(i+1);
}

//计算上界函数
double bound(int i)
{
    double leftw= c-cw;
    double b =cp;
    
    for(int k=i;k<=n;k++){//剩余物品重量、价值分别存在w2、v2数组中 
             w2[k]=w[k];
             v2[k]=v[k];
             } 
    knapsack(i);//将剩余物品按单位重量价值排序
    
    while(i<=n&&w2[i]<=leftw)//将剩余已排好序的物品装入背包 
    {
       leftw-=w2[i];
       b+=v2[i];
       i++;
    }
    if(i<=n)
       b+=v2[i]/w2[i]*leftw;
    return b;
}


int main()
{
    int i; 
    cin >> n >> c;//输入物品数量n、背包容量c   
    for(i=1;i<=n;i++)
    {
       cin >> w[i] >> v[i];//输入各个物品重量wi、价值vi  
       perp[i]=v[i]/w[i];  
       w2[i]=v2[i]=0;       
       x[i]=0;
       best[i]=0;
    }
        
    backtrack(1);
    cout << "最大价值为:" << bestp << endl;
    cout << "需要装入的物品编号是:" << endl;
    for(i=1;i<=n;i++)
    {
       if(best[i])
           cout << i << " ";
    }
    cout << endl;
    system("pause"); 
    return 0;
}

运行结果:

回溯法解01背包问题_01背包问题回溯法伪代码

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/179079.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Android退出APP时如何同时结束APP进程

    Android退出APP时如何同时结束APP进程1.在退出APP的代码逻辑里加入以下代码:ActivityManageram=(ActivityManager)getSystemService(ACTIVITY_SERVICE);am.killBackgroundProcesses(“包名”);//API至少为8才能使用2.添加权限

    2022年7月17日
    13
  • jQuery数据类型总结建议收藏

    jQuery除了包含原生JS中的内置数据类型(built-indatatype),还包括一些扩展的数据类型(virtualtypes),如Selectors、Events等。1.StringS

    2021年12月21日
    31
  • idea debug断点调试技巧_idea断点查看选中的值

    idea debug断点调试技巧_idea断点查看选中的值文章目录一.怎么开启断点调试?二.调试界面咋那么多按钮?1.返回断点位置2.步过3.步入4,5.强制步入,步出6.回退断点7.断点跳到光标处8.表达式计算9.恢复程序10.停止程序11.查看所有断点12.禁用断点13.其他三.竟然有那么多调试断点?1.方法断点2.属性断点3.异常断点4.终止断点5.条件断点6.流断点7.多线程断点8.远程断点一.怎么开启断点调试?随着开发的深入,越来越觉得高效的调试方法是多么的重要了,但我们一般上来就是敲一些代码,谁会去静下心来学一些看似没什么用的调试技巧呢?

    2022年8月30日
    1
  • Werkzeug库[通俗易懂]

    Werkzeug库[通俗易懂]简介Werkzeug是一个Python写成的WSGI工具集。它遵循WSGI规范,对服务器和Web应用之间的“中间层”进行了开发,衍生出一系列非常有用的Web服务底层模块。关于Werkzeug功能的最简单的一个例子如下:12345678910fromwerkzeug.wrappersimportRequest,…

    2022年9月27日
    0
  • webapp开发框架[通俗易懂]

    webapp开发框架[通俗易懂]前言快速增长的APP应用软件市场,以及智能手机的普及,手机应用:Native(原生)APP快速占领了APP市场,成为了APP开发的主流,但其平台的不通用性,开发成本高,多版本开发等问题,一直困扰着专业APP开发企业,和APP服务提供商。安卓和IOS的操作方式,开发模式,界面UI显示方面的差别,也使得原生APP的不同版本体验有很大的区别,光是做兼容性调测,都要花费开发企业不少的时间。近年来,另一种应用形态——基于HTML5技术的WebApp也如雨后春笋般出现,于是关于原生APP与HTML5APP

    2022年4月19日
    99
  • 激光测距传感器原理与应用介绍

    激光测距传感器原理与应用介绍激光,英文名称为LightAmplificationbyStimulatedEmissionofRadiation(简称LASER),意思为原子受激辐射的光,故称激光,激光的产生原理,是原子中的电子吸收能量后从低能级跃迁到高能级,再从高能级回落到低能级的时候,所释放的能量以光子的形式放出,被引诱(激发)出来的光子束(激光)。激光与普通光源相比,具有单色性、高亮度、方向性等优势,被广泛应用于工业生产和科研实验等各个领域,激光测距便是其中应用较为广泛的一项技术。1.激光测距技术的特点激光

    2022年5月29日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号