项目结构:

Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:03
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : bead.go
*/
package dto
// BeadItem 多宝手串珠子实体
type BeadItem struct {
BeadID string
Name string
Material string
ColorGroup string // red/green/purple/gold
UnitPrice float64
Stock int
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:03
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : jewelry.go
*/
package dto
// JewelryItem 成套首饰商品
type JewelryItem struct {
SkuID string
Name string
Category string // necklace / earring / bracelet / ring
Material string // Au999 / 18K / S925
Color string
Style string
Price float64
Stock int
HasGem bool
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:04
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : bracelet_rule.go
*/
package rule
import "goalgorithms/backtracking/dto"
// BraceletRule 手串搭配约束
type BraceletRule struct {
MaxSingleColor int
}
func (r *BraceletRule) Check(item dto.BeadItem, path []dto.BeadItem) bool {
// 1.库存校验
used := 0
for _, p := range path {
if p.BeadID == item.BeadID {
used++
}
}
if used >= item.Stock {
return false
}
// 2.色系均衡限制
colorCnt := make(map[string]int)
for _, b := range path {
colorCnt[b.ColorGroup]++
}
if colorCnt[item.ColorGroup] >= r.MaxSingleColor {
return false
}
return true
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:04
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : scene_jewelry_rule.go
*/
package rule
import "goalgorithms/backtracking/dto"
// SceneConfig 场景配置
type SceneConfig struct {
AllowMaterial map[string]bool
MustGem bool
}
// SceneJewelryRule 场景首饰规则
type SceneJewelryRule struct {
conf SceneConfig
}
func NewSceneJewelryRule(conf SceneConfig) *SceneJewelryRule {
return &SceneJewelryRule{conf: conf}
}
func (r *SceneJewelryRule) Check(item dto.JewelryItem, path []dto.JewelryItem) bool {
if item.Stock <= 0 {
return false
}
if !r.conf.AllowMaterial[item.Material] {
return false
}
if r.conf.MustGem && !item.HasGem {
return false
}
return true
}
// GetSceneConfig 场景配置中心,新增场景只在这里扩展
func GetSceneConfig(sceneType string) SceneConfig {
sceneMap := map[string]SceneConfig{
"wedding": {
AllowMaterial: map[string]bool{"Au999": true, "18K": true},
MustGem: true,
},
"commute": {
AllowMaterial: map[string]bool{"Au999": true, "S925": true, "18K": true},
MustGem: false,
},
"dinner": {
AllowMaterial: map[string]bool{"18K": true},
MustGem: true,
},
}
cfg, ok := sceneMap[sceneType]
if !ok {
return sceneMap["commute"]
}
return cfg
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:05
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : score_util.go
*/
package common
import "goalgorithms/backtracking/dto"
// ScoreBraceletScheme 手串方案评分
func ScoreBraceletScheme(scheme []dto.BeadItem) float64 {
colorSet := make(map[string]bool)
var totalCost float64
for _, b := range scheme {
colorSet[b.ColorGroup] = true
totalCost += b.UnitPrice
}
diversity := float64(len(colorSet))
return diversity*10 - totalCost/200
}
// ScoreJewelryScheme 成套首饰方案评分
func ScoreJewelryScheme(scheme []dto.JewelryItem) float64 {
gemCnt := 0
stockScore := 0
for _, item := range scheme {
if item.HasGem {
gemCnt++
}
if item.Stock < 5 {
stockScore += item.Stock
} else {
stockScore += 5
}
}
return float64(gemCnt*5 + stockScore)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:05
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : backtrack_bracelet.go
*/
package core
import (
"goalgorithms/backtracking/dto"
"goalgorithms/backtracking/rule"
)
// BraceletBackTracker 手串回溯器
type BraceletBackTracker struct {
beadPool []dto.BeadItem
rule *rule.BraceletRule
solutions [][]dto.BeadItem
}
func NewBraceletBackTracker(pool []dto.BeadItem, r *rule.BraceletRule) *BraceletBackTracker {
return &BraceletBackTracker{
beadPool: pool,
rule: r,
}
}
func (bt *BraceletBackTracker) backtrack(path []dto.BeadItem, remain int, totalCost float64, budget float64) {
if remain == 0 {
cp := make([]dto.BeadItem, len(path))
copy(cp, path)
bt.solutions = append(bt.solutions, cp)
return
}
if totalCost > budget {
return
}
for _, bead := range bt.beadPool {
if !bt.rule.Check(bead, path) {
continue
}
path = append(path, bead)
bt.backtrack(path, remain-1, totalCost+bead.UnitPrice, budget)
path = path[:len(path)-1]
}
}
func (bt *BraceletBackTracker) Run(targetCount int, budget float64) [][]dto.BeadItem {
bt.solutions = make([][]dto.BeadItem, 0)
bt.backtrack([]dto.BeadItem{}, targetCount, 0.0, budget)
return bt.solutions
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:06
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : backtrack_jewelry.go
*/
package core
import (
"goalgorithms/backtracking/dto"
"goalgorithms/backtracking/rule"
)
// JewelrySceneBackTracker 首饰成套回溯器
type JewelrySceneBackTracker struct {
goodsPool []dto.JewelryItem
rule *rule.SceneJewelryRule
solutions [][]dto.JewelryItem
}
func NewJewelrySceneBackTracker(pool []dto.JewelryItem, r *rule.SceneJewelryRule) *JewelrySceneBackTracker {
return &JewelrySceneBackTracker{
goodsPool: pool,
rule: r,
}
}
func (bt *JewelrySceneBackTracker) backtrack(startIdx int, selected []dto.JewelryItem, totalPrice float64, budget float64, targetCategories map[string]bool) {
// 判断是否集齐目标品类
selectedCats := make(map[string]bool)
for _, item := range selected {
selectedCats[item.Category] = true
}
complete := true
for cat := range targetCategories {
if !selectedCats[cat] {
complete = false
break
}
}
if complete {
cp := make([]dto.JewelryItem, len(selected))
copy(cp, selected)
bt.solutions = append(bt.solutions, cp)
return
}
if totalPrice > budget {
return
}
for i := startIdx; i < len(bt.goodsPool); i++ {
item := bt.goodsPool[i]
if selectedCats[item.Category] {
continue
}
if !bt.rule.Check(item, selected) {
continue
}
selected = append(selected, item)
bt.backtrack(i+1, selected, totalPrice+item.Price, budget, targetCategories)
selected = selected[:len(selected)-1]
}
}
func (bt *JewelrySceneBackTracker) Run(budget float64, targetCategories map[string]bool) [][]dto.JewelryItem {
bt.solutions = make([][]dto.JewelryItem, 0)
bt.backtrack(0, []dto.JewelryItem{}, 0.0, budget, targetCategories)
return bt.solutions
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:06
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : bracelet_service.go
*/
package service
import (
"goalgorithms/backtracking/common"
"goalgorithms/backtracking/core"
"goalgorithms/backtracking/dto"
"goalgorithms/backtracking/rule"
"sort"
)
// BraceletMatchService 手串搭配业务服务
type BraceletMatchService struct {
beadPool []dto.BeadItem
}
func NewBraceletMatchService(pool []dto.BeadItem) *BraceletMatchService {
return &BraceletMatchService{beadPool: pool}
}
func (svc *BraceletMatchService) Match(targetCount int, budget float64, maxColorLimit int, topN int) [][]dto.BeadItem {
r := &rule.BraceletRule{MaxSingleColor: maxColorLimit}
tracker := core.NewBraceletBackTracker(svc.beadPool, r)
schemes := tracker.Run(targetCount, budget)
// 打分排序
sort.Slice(schemes, func(i, j int) bool {
return common.ScoreBraceletScheme(schemes[i]) > common.ScoreBraceletScheme(schemes[j])
})
if len(schemes) > topN {
schemes = schemes[:topN]
}
return schemes
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:07
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : jewelry_scene_service.go
*/
package service
import (
"goalgorithms/backtracking/common"
"goalgorithms/backtracking/core"
"goalgorithms/backtracking/dto"
"goalgorithms/backtracking/rule"
"sort"
)
// JewelrySceneMatchService 场景首饰搭配服务
type JewelrySceneMatchService struct {
goodsPool []dto.JewelryItem
}
func NewJewelrySceneMatchService(pool []dto.JewelryItem) *JewelrySceneMatchService {
return &JewelrySceneMatchService{goodsPool: pool}
}
func (svc *JewelrySceneMatchService) MatchByScene(scene string, budget float64, targetCategories map[string]bool, topN int) [][]dto.JewelryItem {
cfg := rule.GetSceneConfig(scene)
r := rule.NewSceneJewelryRule(cfg)
tracker := core.NewJewelrySceneBackTracker(svc.goodsPool, r)
schemes := tracker.Run(budget, targetCategories)
sort.Slice(schemes, func(i, j int) bool {
return common.ScoreJewelryScheme(schemes[i]) > common.ScoreJewelryScheme(schemes[j])
})
if len(schemes) > topN {
schemes = schemes[:topN]
}
return schemes
}
调用:
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Backtracking Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/7/23 7:07
# User : geovindu
# Product : GoLand
# Project : goalgorithms
# File : backtrackingbll.go
*/
package bll
import (
"fmt"
"goalgorithms/backtracking/dto"
"goalgorithms/backtracking/service"
)
func testBraceletMatch() {
beadPool := []dto.BeadItem{
{BeadID: "B01", Name: "南红圆珠", Material: "南红", ColorGroup: "red", UnitPrice: 168, Stock: 4},
{BeadID: "B02", Name: "和田玉圆珠", Material: "和田玉", ColorGroup: "green", UnitPrice: 198, Stock: 5},
{BeadID: "B03", Name: "紫水晶", Material: "紫水晶", ColorGroup: "purple", UnitPrice: 128, Stock: 4},
{BeadID: "B04", Name: "足金隔珠", Material: "足金", ColorGroup: "gold", UnitPrice: 320, Stock: 3},
}
svc := service.NewBraceletMatchService(beadPool)
result := svc.Match(8, 2000, 4, 6)
fmt.Println("===== 多宝手串搭配方案 =====")
for idx, scheme := range result {
var total float64
var names []string
for _, b := range scheme {
total += b.UnitPrice
names = append(names, b.Name)
}
fmt.Printf("方案%d 总价:%.2f 珠子:%v\n", idx+1, total, names)
}
}
func testJewelrySceneMatch() {
goodsPool := []dto.JewelryItem{
{SkuID: "N001", Name: "碎钻项链", Category: "necklace", Material: "18K", Color: "white", Style: "luxury", Price: 3299, Stock: 12, HasGem: true},
{SkuID: "N003", Name: "素金项链", Category: "necklace", Material: "Au999", Color: "yellow", Style: "minimalist", Price: 2199, Stock: 9, HasGem: false},
{SkuID: "E001", Name: "白钻耳饰", Category: "earring", Material: "18K", Color: "white", Style: "luxury", Price: 2199, Stock: 15, HasGem: true},
{SkuID: "E003", Name: "素金耳饰", Category: "earring", Material: "Au999", Color: "yellow", Style: "minimalist", Price: 1399, Stock: 11, HasGem: false},
}
svc := service.NewJewelrySceneMatchService(goodsPool)
targetCats := map[string]bool{"necklace": true, "earring": true}
fmt.Println("\n===== 婚嫁场景 =====")
wedding := svc.MatchByScene("wedding", 8000, targetCats, 8)
for _, set := range wedding {
var names []string
var total float64
for _, item := range set {
names = append(names, item.Name)
total += item.Price
}
fmt.Printf("%v 总价 %.2f\n", names, total)
}
fmt.Println("\n===== 通勤场景 =====")
commute := svc.MatchByScene("commute", 5000, targetCats, 8)
for _, set := range commute {
var names []string
var total float64
for _, item := range set {
names = append(names, item.Name)
total += item.Price
}
fmt.Printf("%v 总价 %.2f\n", names, total)
}
}
func BacktrackingMain() {
testBraceletMatch()
testJewelrySceneMatch()
}
介绍了一个基于回溯算法的珠宝搭配系统实现,主要包含:
- 数据结构定义:BeadItem(手串珠子)和JewelryItem(成套首饰)的实体结构
- 规则引擎:BraceletRule(手串搭配约束)和SceneJewelryRule(场景首饰规则)
- 回溯算法核心:分别实现了手串搭配和场景首饰搭配的回溯算法
- 服务层:提供BraceletMatchService和JewelrySceneMatchService业务服务
- 评分系统:根据颜色多样性、库存状况等指标对搭配方案进行评分排序
系统支持特定场景(婚嫁、通勤等)的珠宝搭配推荐,并考虑预算、库存等约束条件,最终输出按评分排序的TopN推荐方案。
输出:
