Files

221 lines
8.4 KiB
Go
Raw Permalink Normal View History

/*
* @Author : huangzj
* @Time : 2020/7/19 20:46
* @Description:深度搜索工具类,在现实问题中,用于比如一组道具,抽取一定数量,必须超过总价值多少,有几种组合方式
* 剪枝策略,参考:https://blog.csdn.net/qq_38790716/article/details/88051412
*/
package deepSearch
type DeepFirstSearch struct {
length int //道具数组长度
vis []bool //标识 --true表示这个节点走过了,false表示这个节点没走过
limitValue int //最小限制值(即抽中的道具需要至少最低保底多少价值)
limitMaxValue int //最大限制值(最大值区间,只用于计算在保底和区间之间的方法中,不超过)
LimitNum int //限制数字的数量(最多只能有几个数字)
sum int //总数值
valueList []ItemValue //道具价值数组
tempList []int //下标数组(用来存储当前对应的道具下标)
itemGroup [][]ItemValue //最终的组合数组
}
func NewDeepSearch() *DeepFirstSearch {
return &DeepFirstSearch{
sum: 0,
}
}
//计算n个道具的所有组合,这个是最原始的深度优先搜索算法
func (srv *DeepFirstSearch) GetItemMatchNum(list []ItemValue, num int) [][]ItemValue {
//不校验数量,如果超过数组的最大数量,就是失败了.返回空数组
srv.length = len(list)
srv.vis = make([]bool, srv.length)
srv.valueList = list
srv.tempList = make([]int, srv.length)
srv.itemGroup = make([][]ItemValue, 0)
srv.LimitNum = num
srv.dfs(0, 0)
return srv.itemGroup
}
//valueList:物品价值数组 一维数组的组成是:[编号,价值]
//limitValue:物品价值限制
//题目可以理解为:有一个长度为n的数组valueList,从其中选择出1~n个元素,保证这些元素相加的值能够至少超过limitValue.
//找到所有对应的组合即可
func (srv *DeepFirstSearch) GetItemMatchValue(list []ItemValue, limit int) [][]ItemValue {
//这边不校验所有的价值总和是否要高于limit,如果没有超过数组就是0,也是符合条件的.
srv.length = len(list)
srv.vis = make([]bool, srv.length)
srv.limitValue = limit
srv.valueList = list
srv.tempList = make([]int, srv.length)
srv.itemGroup = make([][]ItemValue, 0)
srv.dfsBeyondValue(0, 0)
return srv.itemGroup
}
//获取限制N个数量的保底计算方法,全面两个参数合和 #GetItemMatchValue# 一致
func (srv *DeepFirstSearch) GetItemMatchValueLimitNum(list []ItemValue, limit int, num int) [][]ItemValue {
//不校验,没有结果返回空数组
srv.length = len(list)
srv.vis = make([]bool, srv.length)
srv.limitValue = limit
srv.valueList = list
srv.tempList = make([]int, srv.length)
srv.itemGroup = make([][]ItemValue, 0)
srv.LimitNum = num
srv.dfsLimitNum(0, 0)
return srv.itemGroup
}
func (srv *DeepFirstSearch) GetItemMatchValueInSection(list []ItemValue, min int, max int) [][]ItemValue {
//不校验,查不到就返回空数组
srv.length = len(list)
srv.vis = make([]bool, srv.length)
srv.limitValue = min
srv.valueList = list
srv.tempList = make([]int, srv.length)
srv.itemGroup = make([][]ItemValue, 0)
srv.limitMaxValue = max
srv.dfsInSection(0, 0)
return srv.itemGroup
}
func (srv *DeepFirstSearch) dfs(step int, pos int) {
//满足条件,添加组合方案
srv.generateGroupDfs(step)
for i := pos; i < srv.length; i++ {
//vis为false表示该位置没有被进入过 &&
if srv.vis[i] == false {
srv.tempList[step] = i
srv.sum = srv.sum + srv.valueList[i].ItemValue //计算总数值,这个是需要到下一个step的dfs中进行判断的
srv.vis[i] = true //该位置已经被进入了,设置为true
srv.dfs(step+1, i+1) //进行下一步的深度搜索
srv.vis[i] = false //搜索结束后返回,标识置为false,表示可以再进入
srv.sum = srv.sum - srv.valueList[i].ItemValue //总数要减掉之前的值,才是现在的值
}
}
return
}
func (srv *DeepFirstSearch) dfsBeyondValue(step int, pos int) {
//满足条件,添加组合方案
srv.generateGroup(step)
for i := pos; i < srv.length; i++ {
//vis为false表示该位置没有被进入过 &&
if srv.vis[i] == false {
srv.tempList[step] = i
srv.sum = srv.sum + srv.valueList[i].ItemValue //计算总数值,这个是需要到下一个step的dfs中进行判断的
srv.vis[i] = true //该位置已经被进入了,设置为true
srv.dfsBeyondValue(step+1, i+1) //进行下一步的深度搜索
srv.vis[i] = false //搜索结束后返回,标识置为false,表示可以再进入
srv.sum = srv.sum - srv.valueList[i].ItemValue //总数要减掉之前的值,才是现在的值
}
}
return
}
func (srv *DeepFirstSearch) dfsInSection(step int, pos int) {
//满足条件,添加组合方案
srv.generateGroupInSection(step)
for i := pos; i < srv.length; i++ {
//vis为false表示该位置没有被进入过 &&
if srv.vis[i] == false {
srv.tempList[step] = i
srv.sum = srv.sum + srv.valueList[i].ItemValue //计算总数值,这个是需要到下一个step的dfs中进行判断的
srv.vis[i] = true //该位置已经被进入了,设置为true
srv.dfsInSection(step+1, i+1) //进行下一步的深度搜索
srv.vis[i] = false //搜索结束后返回,标识置为false,表示可以再进入
srv.sum = srv.sum - srv.valueList[i].ItemValue //总数要减掉之前的值,才是现在的值
}
}
return
}
func (srv *DeepFirstSearch) dfsLimitNum(step int, pos int) {
//满足条件,添加组合方案
srv.generateGroupLimitNum(step)
for i := pos; i < srv.length; i++ {
//vis为false表示该位置没有被进入过 &&
if srv.vis[i] == false {
srv.tempList[step] = i
srv.sum = srv.sum + srv.valueList[i].ItemValue //计算总数值,这个是需要到下一个step的dfs中进行判断的
srv.vis[i] = true //该位置已经被进入了,设置为true
srv.dfsLimitNum(step+1, i+1) //进行下一步的深度搜索
srv.vis[i] = false //搜索结束后返回,标识置为false,表示可以再进入
srv.sum = srv.sum - srv.valueList[i].ItemValue //总数要减掉之前的值,才是现在的值
}
}
return
}
//满足条件,添加组合方案
func (srv *DeepFirstSearch) generateGroupDfs(step int) {
//这边不直接return是因为可能后面还有元素没进组合,这个也是允许的,所有的组合,如果直接return的话,我搜索到[1,2,3]满足就不会再去搜索[1,2,3,4].
if step == srv.LimitNum {
itemList := make([]ItemValue, 0)
for i := 0; i < step; i++ {
itemList = append(itemList, srv.valueList[srv.tempList[i]])
}
srv.itemGroup = append(srv.itemGroup, itemList)
}
}
//满足条件,添加组合方案
func (srv *DeepFirstSearch) generateGroup(step int) {
//这边不直接return是因为可能后面还有元素没进组合,这个也是允许的,所有的组合,如果直接return的话,我搜索到[1,2,3]满足就不会再去搜索[1,2,3,4].
if srv.sum >= srv.limitValue {
itemList := make([]ItemValue, 0)
for i := 0; i < step; i++ {
itemList = append(itemList, srv.valueList[srv.tempList[i]])
}
srv.itemGroup = append(srv.itemGroup, itemList)
}
}
//满足条件,添加组合方案
func (srv *DeepFirstSearch) generateGroupLimitNum(step int) {
//这边不直接return是因为可能后面还有元素没进组合,这个也是允许的,所有的组合,如果直接return的话,我搜索到[1,2,3]满足就不会再去搜索[1,2,3,4].
if srv.sum >= srv.limitValue && step == srv.LimitNum {
itemList := make([]ItemValue, 0)
for i := 0; i < step; i++ {
itemList = append(itemList, srv.valueList[srv.tempList[i]])
}
srv.itemGroup = append(srv.itemGroup, itemList)
}
}
//满足条件,添加组合方案
func (srv *DeepFirstSearch) generateGroupInSection(step int) {
//这边不直接return是因为可能后面还有元素没进组合,这个也是允许的,所有的组合,如果直接return的话,我搜索到[1,2,3]满足就不会再去搜索[1,2,3,4].
if srv.sum >= srv.limitValue && srv.sum <= srv.limitMaxValue {
itemList := make([]ItemValue, 0)
for i := 0; i < step; i++ {
itemList = append(itemList, srv.valueList[srv.tempList[i]])
}
srv.itemGroup = append(srv.itemGroup, itemList)
}
}