博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
0-1背包问题-回溯&贪心算法-C#Demo
阅读量:4167 次
发布时间:2019-05-26

本文共 4129 字,大约阅读时间需要 13 分钟。

概述

     回溯算法的效率不是很高,就起本质而言,属于穷举,不同的是提供了一个穷举的思路:回溯。回溯算法也称试探法,基本思想是:从一条路往前走,能进则进。

what

     回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:

    1.找到一个可能存在的正确的答案
    2.在尝试了所有可能的分步方法后宣告该问题没有答案

特点

     深度搜索,确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。这个开始结点就成为一个活结点,同时也成为当前的扩展结点。在当前的扩展结点处,搜索向纵深方向移至一个新结点。这个新结点就成为一个新的活结点,并成为当前扩展结点。如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。

     剪枝,回溯法是一个即带有系统性又带有跳跃性的搜索算法,当节点肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯,剪枝使得回溯算法效率提高了。

     有去有回,去按照深度遍历,回体现了回溯的思想。


C# Demo

     对于回溯的理解,是在代码的基础上不断加深的,分享一下自己写的代码,希望大家可以拍砖斧正~

#region 回溯+贪心--刘雅雯--2017年9月26日21:36:29        ///         /// 从K节点扩展下去,计算得到的最大价值        ///         ///         ///         ///         ///         ///         /// 最大价值        /// 背包使用的容量        /// k节点        /// 
float Bound(float[] values, float[] weight, float[] VW, int n, float W, float Profit_Gained, float weight_Used, int k) { int i; for ( i = k+1; i
/// /// ///
///
///
///
///
///
int[,] Knapsack(float[] values, float[] weight, float[] VW, int n, float W) { int count=0; //存可行解 int[,] result = new int[9,8]; int[,] Newresult = new int[9, 8]; float current_weight = 0; //背包当前的使用重量 float current_profit = 0; float Weight = 0; //最终背包的使用重量 float Profit = -1; //背包最终的价值 @@@@和current_profit关系 int index = 0; int[] status = new int[9]; int[] newStatus=new int[8]; while (true) //@@@可以省略吗,如果省略的话要有一个回调的函数在这里调用,保证向后循环 { while (index
=n) //@@@物品放完了???回答:物品判断完了最后一个 { Weight= current_weight; Profit = current_profit; index = n; for (int i = 0; i < n; i++) { newStatus[i] =status[i]; //物品的状态重新保存 } } else { status[index] = 0; // 不在包中,状态为0 } while(Bound(values,weight,VW,n,W,current_profit,current_weight,index)<=Profit) //@@@何时满足条件,第一次满足:遍历完物品,之后条件不固定 { //当>的时候说明有继续追踪的必要,可能会放进包中 //当<=的时候,说明该节点没有扩展的必要了,可以剪枝 //装下可行性的结果 for (int j = 0; j < newStatus.Length; j++) { result[count, j] = newStatus[j]; } count++; while (index!=0 && status[index]!=1)//@@@!=1是什么样的节点?物品没有放进去的节点 相当于出口 { index--; } if (index==0) { return result; } status[index] = 0; //1的情况已经考虑,现在要考虑O的情况了 current_weight -= weight[index]; current_profit -= values[index]; } index++; //遍历 } } #endregion

     调用方式如下:

private void backtracking_Click(object sender, EventArgs e)        {            //物品容量和价值的对应            float[] value = new float[8] { 11, 21, 31, 33, 43, 53, 55, 65 };            float[] weight = new float[8] { 1, 11, 21, 23, 33, 43, 45, 55 };            float[] VM = new float[8] { 11, 1.9F,1.5F,1.4F,1.3F,1.23F,1.2F,1.2F };            int[,] c = new int[0,0];            c = Knapsack(value, weight, VM, 8, 110);            for (int i = 0; i < c.Length/8; i++)            {                for (int j = 0; j < 8; j++)                {                    labBacktracking.Text = labBacktracking.Text + c[i, j].ToString() + ",";                }                labBacktracking.Text = labBacktracking.Text + "\r\n";            }        }

结语

     算法我们要从不同的角度去深入和了解,不断的思考,每次会有不同的体会。

这里写图片描述

你可能感兴趣的文章
Redis数据结构之字典
查看>>
Redis哈希键冲突问题
查看>>
邮件报 535 5.7.0 Error: authentication failed
查看>>
Redis数据结构之跳跃表
查看>>
Linux定时调度crontab
查看>>
Spark释义Dataset、DataFrame、SQL
查看>>
Spark作业调度类型
查看>>
hive表修改map分隔符
查看>>
Rpc框架(一)要点介绍
查看>>
Container killed on request. Exit code is 143
查看>>
Hadoop误删文件后恢复
查看>>
Hive Exceeded MAX_FAILED_UNIQUE_FETCHES; bailing-out.
查看>>
eclipse添加hadoop插件连接HDFS
查看>>
flume常见报错记录
查看>>
flume知识点归纳
查看>>
Java知识点归纳
查看>>
idea行号栏太宽的问题
查看>>
java 异常java.lang.UnsupportedOperationException
查看>>
EmptyList和Arrays$ArrayLit使用介绍
查看>>
Java多线程相关(1) 线程
查看>>