01背包问题c语言代码回溯法

合集下载

回溯算法解决0-1背包问题(DOC)

回溯算法解决0-1背包问题(DOC)

《算法分析与设计》实验报告2015-2016年第2学期实验班级:学生姓名:学号:指导老师:信息工程学院实验项目名称:回溯算法解决0-1背包问题实验日期:2016年5 月18 日一、实验类型:□√验证性□设计性二、实验目的掌握0—1背包问题的回溯算法三、实验内容及要求给定n种物品和一背包。

物品i的重量是wi,其价值为vi,背包的容量为C。

问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?四、实验步骤#include<iostream>using namespace std;class Knap{ friend int Knapsack(int p[],int w[],int c,int n );public:void print(){for(int m=1;m<=n;m++){ cout<<bestx[m]<<" ";}cout<<endl;};private:int Bound(int i);void Backtrack(int i);int c;//背包容量int n; //物品数int *w;//物品重量数组int *p;//物品价值数组int cw;//当前重量int cp;//当前价值int bestp;//当前最优值int *bestx;//当前最优解int *x;//当前解};int Knap::Bound(int i){//计算上界int cleft=c-cw;//剩余容量int b=cp;//以物品单位重量价值递减序装入物品while(i<=n&&w[i]<=cleft){cleft-=w[i];b+=p[i];i++;}//装满背包if(i<=n)b+=p[i]/w[i]*cleft;return b;}void Knap::Backtrack(int i){if(i>n){if(bestp<cp){ for(int j=1;j<=n;j++)bestx[j]=x[j];bestp=cp;}return;}if(cw+w[i]<=c) //搜索左子树{ x[i]=1;cw+=w[i];cp+=p[i];Backtrack(i+1);cw-=w[i];cp-=p[i];}if(Bound(i+1)>bestp)//搜索右子树{ x[i]=0;Backtrack(i+1);}}class Object{friend int Knapsack(int p[],int w[],int c,int n); public:int operator<=(Object a)const{ return (d>=a.d);}private:int ID;float d;};int Knapsack(int p[],int w[],int c,int n){ //为Knap::Backtrack初始化int W=0;int P=0;int i=1;Object *Q=new Object[n]; for(i=1;i<=n;i++){ Q[i-1].ID=i;Q[i-1].d=1.0*p[i]/w[i];P+=p[i];W+=w[i];}if(W<=c)return P;//装入所有物品//依物品单位重量排序float f;for( i=0;i<n;i++)for(int j=i;j<n;j++){if(Q[i].d<Q[j].d){f=Q[i].d;Q[i].d=Q[j].d;Q[j].d=f;}}Knap K;K.p = new int[n+1];K.w = new int[n+1];K.x = new int[n+1];K.bestx = new int[n+1];K.x[0]=0;K.bestx[0]=0;for( i=1;i<=n;i++){ K.p[i]=p[Q[i-1].ID];K.w[i]=w[Q[i-1].ID];}K.cp=0;K.cw=0;K.c=c;K.n=n;K.bestp=0;//回溯搜索K.Backtrack(1);K.print();delete [] Q;delete [] K.w;delete [] K.p;return K.bestp;}void main(){int *p;int *w; int c=0;int n=0;int i=0; cout<<"请输入背包个数:"<<endl; cin>>n;p=new int[n+1];w=new int[n+1];p[0]=0;w[0]=0;cout<<"请输入各背包的价值:"<<endl; for(i=1;i<=n;i++)cin>>p[i];cout<<"请输入各背包的重量:"<<endl; for(i=1;i<=n;i++)cin>>w[i];cout<<"请输入背包容量:"<<endl; cin>>c;cout<<Knapsack(p,w,c,n)<<endl;}五、实验结果1、实验图形2、结果分析输入背包个数为4个,背包价值分别为30 25 26 15,背包重量分别为4 2 3 1,背包的容量分别为1 2 3 4,则得出的背包算法为0 0 0 1,最优值为15。

01背包问题回溯法c语言

01背包问题回溯法c语言

01背包问题回溯法c语言01背包问题是一个经典的动态规划问题,可以使用回溯法来解决。

在C语言中,我们可以通过递归的方式来实现回溯法解决01背包问题。

首先,让我们来看一下01背包问题的描述:给定n个物品,每个物品有一个重量和一个价值。

现在有一个背包,它能够容纳一定的重量,问如何选择装入背包的物品,使得背包中物品的总价值最大。

接下来,让我们来看一下如何使用回溯法来解决这个问题。

我们可以定义一个递归函数来尝试将每个物品放入背包或者不放入背包,然后找出最优解。

以下是一个简单的C语言代码示例:c.#include <stdio.h>。

#define N 5 // 物品的数量。

#define W 10 // 背包的容量。

int weight[N] = {2, 2, 6, 5, 4}; // 每个物品的重量。

int value[N] = {6, 3, 5, 4, 6}; // 每个物品的价值。

int maxValue = 0; // 最大的总价值。

void backtrack(int index, int currentWeight, int totalValue) {。

if (index == N || currentWeight == W) {。

if (totalValue > maxValue) {。

maxValue = totalValue;}。

return;}。

// 不放入背包。

backtrack(index + 1, currentWeight, totalValue); // 放入背包。

if (currentWeight + weight[index] <= W) {。

backtrack(index + 1, currentWeight +weight[index], totalValue + value[index]);}。

}。

int main() {。

backtrack(0, 0, 0);printf("背包能够容纳的最大总价值为,%d\n", maxValue);return 0;}。

回溯法解决0-1背包问题

回溯法解决0-1背包问题

回溯法解决0-1背包问题问题描述: 有n件物品和⼀个容量为c的背包。

第i件物品的价值是v[i],重量是w[i]。

求解将哪些物品装⼊背包可使价值总和最⼤。

所谓01背包,表⽰每⼀个物品只有⼀个,要么装⼊,要么不装⼊。

回溯法: 01背包属于找最优解问题,⽤回溯法需要构造解的⼦集树。

在搜索状态空间树时,只要左⼦节点是可⼀个可⾏结点,搜索就进⼊其左⼦树。

对于右⼦树时,先计算上界函数,以判断是否将其减去,剪枝啦啦!上界函数bound():当前价值cw+剩余容量可容纳的最⼤价值<=当前最优价值bestp。

为了更好地计算和运⽤上界函数剪枝,选择先将物品按照其单位重量价值从⼤到⼩排序,此后就按照顺序考虑各个物品。

#include <stdio.h>#include <conio.h>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 order[100];//物品编号int put[100];//设置是否装⼊//按单位价值排序void knapsack(){int i,j;int temporder = 0;double temp = 0.0;for(i=1;i<=n;i++)perp[i]=v[i]/w[i];for(i=1;i<=n-1;i++){for(j=i+1;j<=n;j++)if(perp[i]<perp[j])//冒泡排序perp[],order[],sortv[],sortw[]{temp = perp[i];perp[i]=perp[i];perp[j]=temp;temporder=order[i];order[i]=order[j];order[j]=temporder;temp = v[i];v[i]=v[j];v[j]=temp;temp=w[i];w[i]=w[j];w[j]=temp;}}}//回溯函数void backtrack(int i){double bound(int i);if(i>n){bestp = cp;return;}if(cw+w[i]<=c){cw+=w[i];cp+=v[i];put[i]=1;backtrack(i+1);cw-=w[i];cp-=v[i];}if(bound(i+1)>bestp)//符合条件搜索右⼦数backtrack(i+1);}//计算上界函数double bound(int i){double leftw= c-cw;double b = cp;while(i<=n&&w[i]<=leftw){leftw-=w[i];b+=v[i];i++;}if(i<=n)b+=v[i]/w[i]*leftw;return b;}int main(){int i;printf("请输⼊物品的数量和容量:");scanf("%d %lf",&n,&c);printf("请输⼊物品的重量和价值:");for(i=1;i<=n;i++){printf("第%d个物品的重量:",i);scanf("%lf",&w[i]);printf("价值是:");scanf("%lf",&v[i]);order[i]=i;}knapsack();backtrack(1);printf("最有价值为:%lf\n",bestp);printf("需要装⼊的物品编号是:");for(i=1;i<=n;i++){if(put[i]==1)printf("%d ",order[i]);}return 0;}时间复杂度分析: 上界函数bound()需要O(n)时间,在最坏的情况下有O(2^n)个右⼦结点需要计算上界,回溯算法backtrack需要的计算时间为O(n2^n)。

01背包各种算法代码实现总结(穷举,贪心,动态,递归,回溯,分支限界)

01背包各种算法代码实现总结(穷举,贪心,动态,递归,回溯,分支限界)

01背包各种算法代码实现总结(穷举,贪⼼,动态,递归,回溯,分⽀限界)2020-05-22所有背包问题实现的例⼦都是下⾯这张图01背包实现之——穷举法:1.我的难点:(1)在⽤穷举法实现代码的时候,我⾃⼰做的时候认为最难的就是怎么将那么多种情况表⽰出来,⼀开开始想⽤for循环进⾏多次嵌套,但是太⿇烦,⽽且还需要不断的进⾏各种标记。

我现在的⽔平实在太菜,然后就在⼀篇中看到⼀个特别巧妙的枚举算法,如下所⽰:int fun(int x[n]){int i;for(i=0;i<n;i++)if(x[i]!=1) {x[i]=1; return;}//从遇到的第⼀位开始,若是0,将其变成1,然后结束for循环,得到⼀种解法else x[i]=0;return;//从第⼀位开始,若是1,将其变成0,然后继续循环,若再循环的时候遇到0,则将其变为1,结束循环。

得到另⼀种解法。

} 虽然我现在也不知道为什么会这样,但是确实是个很好的规律,找到这个规律后,就可以很轻松的⾃⼰写出各种排列情况,以后遇到排列的问题,就⽤这个⽅法。

语⾔不好描述,上图⽚演⽰(是歪的,凑活看吧。

):(2)算法思想:x[i]的值为0/1,即选或者不选w[i]的值表⽰商品i的重量v[i]的值表⽰商品的价值所以这个算法最核⼼的公式就是tw=x[1]*w[1]+x[2]*w[2]+.......+x[n]*w[n]tv=x[1]*w[1]+x[2]*v[2]+......+x[n]*v[n]tv1:⽤于存储当前最优解limit:背包容量如果 tw<limit&&tv>tv1 则可以找到最优解2.代码实现(借鉴)#include<stdio.h>#include<iostream>using namespace std;#define n 4void possible_solution(int x[n]){int i;for(i=0;i<4;i++) //n=4,有2^4-1种解法if(x[i]!=1){x[i]=1;return; //从遇到的第⼀位开始,若是0,将其变成1,然后结束循环,得到⼀种解法}elsex[i]=0;return;//从第⼀位开始,若是1,将其变成0,然后继续循环,若再循环的时候遇到0,则将其变为1,结束循环。

01背包

01背包

一、回溯法回溯法是一种很低效的方法,有点类似穷举,需要尝试每一种可能,直到找到正确答案,或者尝试完所有的可能。

如果发现某一条路行不通,就往回走。

使用回溯法前最好确定是可行的,且能在有限的时间内完成。

二、实例:四皇后问题有一个4x4的棋盘,上面摆四个皇后,要求每个皇后都不能被攻击。

int pl[3][3] = {0};//建立二维一个数组作为棋盘int state = 0;//记录状态int p[3] = {0};//计数器bool safe();//用这个函数检查是否有皇后会被攻击void fe(){if(state<3){pl[p[state]][state] = 1;int safe = safe();if(safe == true){state++;}else{pl[p[state]][state] = 0;if(p[state] == 3){p[state]=0;state++;fe();return;}else{p[state]++;fe();return;}}}else{return;}}思路如下,先尝试每一行第一个位置,如果没问题,再尝试下一行,如果出了问题,改成下一个位置,如果本行已经尝试完,说明问题在上一行。

N皇后问题都可以参考这个,注意由于大量实验证明4皇后问题有解,所以没有对一些异常加以防范。

0-1背包问题不同求解方法关键字: 0-1背包问题不同求解方法一.动态规划求解0-1背包问题/********************************************************** **************//* 0-1背包问题:/* 给定n种物品和一个背包/* 物品i的重量为wi,其价值为vi/* 背包的容量为c/* 应如何选择装入背包的物品,使得装入背包中的物品/* 的总价值最大?/* 注:在选择装入背包的物品时,对物品i只有两种选择,/* 即装入或不装入背包。

用回溯法解决01背包问题

用回溯法解决01背包问题

#include<stdio.h> int c; // 背包含量int n; // 物件数int weight[100]; // 寄存 n 个物件重量的数组int price[100]; // 寄存 n 个物件价值的数组int currentWeight=0; // 目前重量int currentPrice=0; // 目前价值int bestPrice=0; // 目前最优值int bestAnswer[100]; // 目前最优解int bp=0;int bA[100]; // 目前最优解int times=0;void Print();void Backtracking(int i){times+=1;if(i>n){Print();if(bestPrice>bp){bp=bestPrice;for(int j=1;j<=n;j++)bA[j]=bestAnswer[j];}return;}if(currentWeight+weight[i]<=c){ // 将物件 i 放入背包,搜寻左子树bestAnswer[i] = 1;currentWeight += weight[i];bestPrice += price[i];Backtracking(i+1); //达成上边的递归,返回到上一结点,物件i 不放入背包,准备递归右子树currentWeight -= weight[i];bestPrice -= price[i];}bestAnswer[i] = 0;Backtracking(i+1);}void Print(){int i;printf("\n 路径为 {");for(i=1;i<n;++i)printf("%d,",bestAnswer[i]);printf("%d}\t 价值为 %d\n",bestAnswer[i],bestPrice); }void main(){int i;/* 输入部分 */printf(" 请输入物件的数目 :\n");scanf("%d",&n);printf(" 请输入背包的容量 (能蒙受的重量 ):\n"); scanf("%d",&c);printf(" 请挨次输入 %d 个物件的重量 :\n",n);for(i=1;i<=n;i++)scanf("%d",&weight[i]);printf(" 请挨次输入 %d 个物件的价值 :\n",n);for(i=1;i<=n;i++)scanf("%d",&price[i]);printf(" 各切合条件的路径为: \n");Backtracking(1);printf("*******************************************************\n"); printf("\n 最优解路径为 {");for(i=1;i<n;++i)printf("%d,",bA[i]);printf("%d}\t 总价值为 %d\n",bA[i],bp);printf("\n\n总合搜寻结点数%d\n",times);}。

蛮力法、动态规划法、回溯法和分支限界法求解01背包问题【精选】

蛮力法、动态规划法、回溯法和分支限界法求解01背包问题【精选】

一、实验内容:分别用蛮力法、动态规划法、回溯法和分支限界法求解0/1背包问题。

注:0/1背包问题:给定种物品和一个容量为的背包,物品的重n C i 量是,其价值为,背包问题是如何使选择装入背包内的物品,使得装i w i v 入背包中的物品的总价值最大。

其中,每种物品只有全部装入背包或不装入背包两种选择。

二、所用算法的基本思想及复杂度分析:1.蛮力法求解0/1背包问题:1)基本思想:对于有n 种可选物品的0/1背包问题,其解空间由长度为n 的0-1向量组成,可用子集数表示。

在搜索解空间树时,深度优先遍历,搜索每一个结点,无论是否可能产生最优解,都遍历至叶子结点,记录每次得到的装入总价值,然后记录遍历过的最大价值。

2)代码:#include<iostream>#include<algorithm>using namespace std;#define N 100//最多可能物体数struct goods //物品结构体{int sign;//物品序号int w;//物品重量int p;//物品价值}a[N];bool m(goods a,goods b){return (a.p/a.w)>(b.p/b.w);}int max(int a,int b){return a<b?b:a;}int n,C,bestP=0,cp=0,cw=0;int X[N],cx[N];/*蛮力法求解0/1背包问题*/int Force(int i){if(i>n-1){if(bestP<cp&&cw+a[i].w<=C){for (int k=0;k<n;k++)X[k]=cx[k];//存储最优路径bestP=cp;}return bestP;}cw=cw+a[i].w;cp=cp+a[i].p;cx[i]=1;//装入背包Force(i+1);cw=cw-a[i].w;cp=cp-a[i].p;cx[i]=0;//不装入背包Force(i+1);return bestP;}int KnapSack1(int n,goods a[],int C,int x[]){Force(0);return bestP;}int main(){goods b[N];printf("物品种数n: ");scanf("%d",&n);//输入物品种数printf("背包容量C: ");scanf("%d",&C);//输入背包容量for (int i=0;i<n;i++)//输入物品i 的重量w 及其价值v {printf("物品%d 的重量w[%d]及其价值v[%d]:",i+1,i+1,i+1);scanf("%d%d",&a[i].w,&a[i].p);b[i]=a[i];}int sum1=KnapSack1(n,a,C,X);//调用蛮力法求0/1背包问题printf("蛮力法求解0/1背包问题:\nX=[ ");for(i=0;i<n;i++)cout<<X[i]<<" ";//输出所求X[n]矩阵printf("]装入总价值%d\n",sum1);bestP=0,cp=0,cw=0;//恢复初始化}3)复杂度分析:蛮力法求解0/1背包问题的时间复杂度为:。

回溯法解决01背包问题

回溯法解决01背包问题
回溯法解决01背包问题
2021/7/1
1
回溯法解决01背包问题
1、算法思想 2、问题描述 3、设计实现
2021/7/1
2
回溯法解决01背包问题
回溯法:是一个既带有系统性又带有跳跃性的的 搜索算法。它在包含问题的所有解的解空间树中,按照 深度优先的策略,从根结点出发搜索解空间树。算法搜 索至解空间树的任一结点时,总是先判断该结点是否肯 定不包含问题的解。如果肯定不包含,则跳过对以该结 点为根的子树的系统搜索,逐层向其原先结点回溯。否 则,进入该子树,继续按深度优先的策略进行搜索。
且在搜索过程中用剪枝函数避免无效搜索;
2021/7/1
4
0/1背包问题概述
在0/1背包问题中,需对容量为c的背包进行装 载。从n个物品中选取装入背包的物品,每件物品
i的重量为wi, 价值为pi。对于可行的背包装载,背包
中的物品的总重量不能超过背包的n 容量,最佳装载
是指所装入的物品价值最高,即 p ix i取得最大值。
课堂上老师已经讲解过用回溯法解决n-皇后问题, m-图着色问题以及哈密顿环问题,他们有相同的特征 即问题的求解目标都是求满足约束条件的全部可行解。 而0/1背包是最优化问题,还需要使用限界函数剪去已 能确认不含最优答案结点的子树。
2021/7/1
3
回溯法解决0/1背包问题
运用回溯法解题通常包含以下三个步骤: a. 针对所给问题,定义问题的解空间; b. 确定易于搜索的解空间结构; c. 以深度优先的方式搜索解空间,并
2021/7/1
14
回溯法解决01背包问题
void Print();
void Backtracking(int i)
{
times+=1;
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

以下是使用C语言实现01背包问题的回溯法代码:
```c
#include <stdio.h>
#include <stdlib.h>
// 初始化背包
struct knapsack {
int maxWeight; // 背包最大承重
int *items; // 物品数组
int n; // 物品数量
};
// 定义物品重量、价值和数量
int weights[] = {2, 2, 6, 5, 4};
int values[] = {6, 3, 5, 4, 6};
int quantities[] = {3, 2, 2, 1, 1};
// 初始化背包最大承重和当前承重
int maxWeight = 10;
int currentWeight = 0;
// 初始化最大价值为0
int maxValue = 0;
// 遍历物品数组
void traverseItems(struct knapsack *knapsack, int index) { // 对于每个物品,遍历其数量
for (int i = 0; i < knapsack->quantities[index]; i++) {
// 如果当前物品可以放入背包装且当前承重不超过背包最大承重,计算放入该物品后的总价值,并更新最大价值
if (currentWeight + weights[index] <= knapsack->maxWeight) {
int currentValue = values[index] * knapsack->quantities[index];
if (currentValue > maxValue) {
maxValue = currentValue;
}
}
// 回溯,将当前物品从背包装中移除,递归地尝试下一个物品
knapsack->quantities[index]--;
if (index < knapsack->n - 1) {
traverseItems(knapsack, index + 1);
}
knapsack->quantities[index]++; // 恢复物品数量,以便下次遍历尝试放入其他物品
}
}
// 主函数
int main() {
// 初始化背包装和物品数组
struct knapsack knapsack = {maxWeight, weights, 5};
knapsack.items = (int *)malloc(sizeof(int) * knapsack.n);
for (int i = 0; i < knapsack.n; i++) {
knapsack.items[i] = values[i] * quantities[i]; // 根据价值和数量计算物品价值,并存储在物品数组中
}
knapsack.n = quantities[4]; // 由于最后一个物品的数量为1,因此只需遍历前n-1个物品即可得到所有可能的结果
// 使用回溯法求解01背包问题,返回最大价值
traverseItems(&knapsack, 0);
printf("The maximum value is %d.\n", maxValue);
free(knapsack.items); // 释放内存空间
return 0;
}
```
希望以上信息能帮助到你。

相关文档
最新文档