回溯法~0-1背包的实现


  1 package 背包;
  2
  3
  4 import java.util.ArrayList;
  5 import java.util.Collections;
  6 import java.util.Comparator;
  7 import java.util.HashMap;
  8 import java.util.Map;
  9 import java.util.Scanner;
 10
 11 public class 背包 {
 12 /*
 13  * 非递归回溯**********************************
 14  * 1.单位性价比,按高到第放入。
 15  * 2.需要变量~固有变量 ~背包容量,物品大小,物品价值,  (物品大小数组,物品价值数组)
 16  * 3.需要变量~判断变量~当前背包容量,当前背包价值,当前最优价值,剩余价值(性价比)
 17  * 4.根据性价比排列物品,降序排序物品。
 18  * 5.hashmap 用于确定物品id。并用于排序
 19  * 6.输出放入的物品时,应将id转化为原数组位置。
 20  * */
 21     static double c; //背包容量
 22     static int n;   //物品数量
 23     static double []p;//  物品价值
 24     static double []p1;// 重新排列的 物品价值
 25     static double []w;//物品大小
 26     static double []w1;//重新排列的物品大小
 27     static double cw; //当前容量
 28     static double cp; //当前价值
 29     static double bestp;//当前最优解
 30     static double []q; //性价比
 31     static double sp; //物品剩余价值
 32     static int[]x; //x[0:i-1]为当前路径
 33     static int[]bestx;//当前最优路径
 34     public static void main(String[] args) {
 35
 36
 37      Scanner sc = new Scanner(System.in);
 38
 39         System.out.println("背包容量");
 40         c=sc.nextInt();
 41         System.out.println("物品数量");
 42         n=sc.nextInt();
 43         double w[]=new double[n];
 44         double p[]=new double[n];
 45
 46         //初始化其他变量
 47          bestp=0;
 48          cw=0;
 49          cp=0;
 50
 51
 52
 53         System.out.println("物品大小");
 54         for(int i = 0 ; i<n;i++)
 55         {
 56             w[i]=sc.nextDouble();
 57         }
 58         System.out.println("物品价值");
 59         {
 60             for(int i = 0 ; i<n;i++)
 61             {
 62                 p[i]=sc.nextDouble();
 63
 64             }
 65         }
 66         //初始化剩余价值
 67         for(int i =0;i<n;i++)
 68         {
 69             sp+=p[i];
 70         }
 71
 72         sc.close();
 73
 74          xjb(p,w,n);
 75
 76
 77
 78
 79     }
 80
 81     //初始化,判断性价比,按降序排列
 82     @SuppressWarnings("unchecked")
 83     public static void xjb (double []p,double[]w,int n)
 84     {
 85         //初始化 ,并降序排序,获得物品的id排序(用来判断物品的优先放入)
 86                 double []q =new double[n];
 87
 88                 for(int i = 0 ; i<n;i++)
 89                 {
 90                     q[i]=p[i]/w[i];
 91                 }
 92
 93        final Map<Integer,Double> map = new HashMap<Integer,Double>();
 94        for(int i = 0;i<n;i++)
 95        {
 96            map.put(i,q[i]);
 97        }
 98        @SuppressWarnings("rawtypes")
 99     ArrayList keys = new ArrayList(map.keySet());//得到key集合
100
101        //把keys排序,但是呢,要按照后面这个比较的规则
102              Collections.sort(keys,new Comparator<Object>(){
103
104                    public int compare(Object o1,Object o2){
105
106            //按照value的值降序排列,若要升序,则这里小于号换成大于号
107                        if(Double.parseDouble(map.get(o1).toString())<Double.parseDouble(map.get(o2).toString()))
108                            return 1;
109
110                        else if(Double.parseDouble(map.get(o1).toString())==Double.parseDouble(map.get(o2).toString()))
111                            return 0;
112
113                        else
114                            return -1;
115                        }
116                    }
117              );
118                System.out.println("***按照性价比排列物品,由大到小排列***"+keys);
119
120
121             double w1[]=new double[n];
122                double p1[]=new double[n];
123         //根绝性价比重新排列物品大小数组。
124          for(int j =0;j<n;j++)
125          {
126
127             w1[j]=w[(Integer) keys.get(j)];
128          }
129
130        //根绝性价比重新排列物品价值数组
131          for(int j =0;j<n;j++)
132          {
133             p1[j]=p[(Integer) keys.get(j)];
134          }
135          System.out.println(beibao01(w1,p1,keys));
136
137     }
138
139
140     @SuppressWarnings("rawtypes")
141     public static double beibao01(double[]w1,double[]p1,ArrayList keys )
142     {
143
144         int i =0;
145         int[]x=new int[n];
146         int[]bestx=new int[n];
147
148       while(true){
149
150         while(i<n&&cw+w1[i]<=c)
151         {//当前空间+此次空间 <=背包容量
152
153             //进入左子树
154             x[i]=1;
155             cw+=w1[i];
156             cp+=p1[i];
157             sp-=p1[i];
158             i++;
159
160           }
161         if(i==n)   //到达叶子节点         ||c==cp 当背包满的时候退出~~
162         {
163             if(cp>bestp){   // 这里居然写反了...!!
164             for(int j =0;j<n;j++)
165             {
166                 bestx[j]=x[j];
167
168             }
169             bestp = cp;
170             }
171         }
172         else
173         {  //既然怒右子树
174             x[i]=0;
175             sp-=w1[i];
176             i++;
177
178         }
179
180
181         while(cp+sp<=bestp)//当前价值+剩余价值>=当前最优解
182         {
183             i--;
184
185             while(i>=0 && x[i]==0) //返回时,若不是第一层且 上一层没有放入载重品。
186             {
187                 //从右子树返回
188                 sp+=w1[i];     //剩余载重恢复上一层数据
189                 i--;   //再次返回更上一层
190
191             }
192             if(i<0)
193             {//若返回至第一层。则,最优解即为bestw。
194
195
196                 for(int j =0;j<n;j++)
197                 {
198                     if(bestx[j]==1)
199                       System.out.println("***放入***"+"w["+keys.get(j)+"]");
200                 }
201                 return bestp;
202             }
203
204             x[i]=0;
205             cw-=w1[i];  //卸下载重
206             cp-=p1[i]; //减少价值
207             i++;  //进入循环, 判断是否 进入左子树
208
209             //进入右子树   ,当返回至 x[i]=1时,既放入载重品,进入右子树,因为左子树已经判断不会有大于当前最优解的方法。
210
211         }
212
213
214     }
215
216     }
217 }
时间: 2024-10-11 22:50:29

回溯法~0-1背包的实现的相关文章

0-1背包-回溯法

算法描述: 0-1背包的回溯法,与装载问题的回溯法十分相似.在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树.当右子树中有可能包含最优解时才进入右子树进行搜索.否则将右子树剪去. 计算右子树上界的更好算法是: 将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包. 算法实现: 由Bound函数计算当前节点处的上界. 类Knap的数据成员记录解空间树的节点信息,以减少参数传递及递归调用所需的栈空间. 在解空间树的当前扩展结点处,仅当要进

0/1背包问题(回溯法)

回溯法是一个既带有系统性又带有跳跃性的搜索算法.它在包含问题的所有解的解空间树中,按深度优先策略,从根结点出发搜索解空间树.算法搜索至解空间树的任意一结点时,先判断该结点是否包含问题的解.如果肯定不包含,则跳过对该结点为根的子树搜索,逐层向其祖先结点回溯:否则 ,进入该子树,继续按深度优先策略搜索. 问题的解空间 用回溯法解问题时,应明确定义问题的解空间.问题的解空间至少包含问题的一个(最优)解.对于 n=3 时的 0/1 背包问题,可用一棵完全二叉树表示解空间,如图所示: 求解步骤 1)针对所

回溯法第6题&mdash;0/1字符串问题

[问题描述]输入仅由0/1组成的长度为n的字符串,并且其中不可含有三个连续的相同子串. 输入:字符串的长度n(n<=40). 输出:所有满足条件的字符串的个数[样例输入] 2 [样例输出] 4 [问题分析]设0/1序列的长度为L,x,y,z分别为第三.第二.第一个子串的首指针:初始:x=L;y=L-1;z=L-2;若三个数字不同,dec(x,1);dec(y,2);dec(z,3);直到 (a[z]...a[y-1]=a[y]...a[x-1]=a[x]...a[l]) or (z<=0)再开

回溯法 -数据结构与算法

1.回溯法算法思想: 定义: 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”. 1.回溯法适用:有许多问题,当需要找出它的解集(全部解)或者要求回答什么解是满足某些约束条件的最优解时,往往要使用回溯法. 2.有组织的穷举式搜索:回溯法的基本做法是搜索或者有的组织穷尽搜索.它能避免搜索所有的可能性.即避免不必要的搜索.这种方

回溯法-01背包问题之一:递归模式

一.回溯法 回溯法是一个既带有系统性又带有跳跃性的搜索算法.它在包含问题的所有解的解空间树中按照深度优先的策略,从根节点出发搜索解空间树.算法搜索至解空间树的任一节点时,总是先判断该节点是否肯定不包含问题的解.如果肯定不包含,则跳过对以该节点为根的子树的系统搜索,逐层向其原先节点回溯.否则,进入该子树,继续按深度优先的策略进行搜索. 运用回溯法解题通常包含以下三个步骤: · 针对所给问题,定义问题的解空间: · 确定易于搜索的解空间结构: · 以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函

回溯法-01背包问题之二:顺序执行模式

上文已讲述了回溯法以及01背包问题的原理,本文讲述如何顺序执行解决01背包问题以及通过模板模式重构软件. 一.顺序执行流程图 图1无剪枝函数的01背包问题顺序执行算法流程图 图2 有剪枝函数的01背包问题顺序执行算法流程图 无剪枝函数是通用的深度遍历算法,为了减少搜索深度可通过剪枝函数处理完全不可能的分枝.与递归方案的区别主要表现在i>=n后需要"回溯",即用后进先出的方式将物品逐个拿出. 二.执行代码 递归与顺序执行方法仅仅是实现方法Backtracking(int i)不同,

回溯法解背包问题分析

先亮出题目: 一,背包问题 及 回溯法解其问题的伪代码 二,赋值后的具体实例 三,如何看懂伪代码 (1)真正了解回溯法的核心思想 我总结的回溯法解题步骤: <1>先找出第一个解 <2>回溯 (2)回溯法核心思想 + 伪代码 + 图9-5 树结构来分析 四,伪代码代入值解析 核心:先找到第一个解,再回溯. cw=0;//背包当前重量 初始值 cp=0;//背包当前价值 初始值 k=1;//第一个物品 n=8;//共8个物品 W=110 第一步:得出第1个可行解: (1)k=1 k=1

回溯法与分支限界

回溯法 1.有许多问题,当需要找出它的解集或者要求回答什么解是满足某些约束条件的最佳解时,往往要使用回溯法. 2.回溯法的基本做法是搜索,或是一种组织得井井有条的,能避免不必要搜索的穷举式搜索法.这种方法适用于解一些组合数相当大的问题. 3.回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树.算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解.如果肯定不包含(剪枝过程),则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯:否则,进入该子树,继续按深度优先策略搜索. 问

回溯法——求解0-1背包问题

以前研究过一个简单的N皇后问题,对回溯法也有了个模糊的认识,大致理解就是:先一直做某件事,当完成某个条件时或者是触犯某个条件时,再返回到最近的一个类似还原点的地方. 在用回溯法求解0-1背包问题的时候,主要遇到三个相对难解决的问题:1,什么是界限函数:2,什么时候用它:3,回溯到哪儿. 什么是界限函数? 如下图: 当我们身在一棵搜索空间树中,站在一个K点举棋不定的时候,我们可以用它估算如果我们继续向下走,我们走完本段路会获得的总价值.假设我们现在有一个最大解,当我用界限函数算出一个价值后和我当前

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

算法描述: 0-1背包的回溯法,与装载问题的回溯法十分相似.在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树.当右子树中有可能包含最优解时才进入右子树进行搜索.否则将右子树剪去. 计算右子树上界的更好算法是: 将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包. 算法实现: 由Bound函数计算当前节点处的上界. 类Knap的数据成员记录解空间树的节点信息,以减少参数传递及递归调用所需的栈空间. 在解空间树的当前扩展结点处,仅当要进