【代码随想录——回溯算法——四周目】

1.重新安排行程

在这里插入图片描述

1.1 我的代码,超时通不过

var (
	used   []bool
	path   []string
	res    []string
	isFind bool
)

func findItinerary(tickets [][]string) []string {
	sortTickets(tickets)
	res = make([]string, len(tickets)+1)
	path = make([]string, 0)
	used = make([]bool, len(tickets))
	isFind = false
	start := "JFK"
	path = append(path, start)
	dfs(start, 0, tickets)
	return res
}

func dfs(start string, num int, tickets [][]string) {
	if isFind {
		return
	}
	if num == len(tickets) {
		copy(res, path)
		isFind = true
		return
	}

	for i := 0; i < len(tickets); i++ {
		// 当前机票未使用,且起点为start
		if !used[i] && tickets[i][0] == start {
			used[i] = true
			path = append(path, tickets[i][1])
			dfs(tickets[i][1], num+1, tickets)
			if isFind {
				return
			}
			path = path[:len(path)-1]
			used[i] = false
		}
	}
}

func sortTickets(tickets [][]string) {
	sort.Slice(tickets, func(i, j int) bool {
		if tickets[i][0] == tickets[j][0] {
			return tickets[i][1] < tickets[j][1]
		}
		return tickets[i][0] < tickets[j][0]
	})
}

1.2 正确的解法

首先先把图的邻接表存进字典,并且按字典序排序,然后从‘JFK’开始深搜,每前进一层就减去一条路径,直到某个起点不存在路径的时候就会跳出while循环进行回溯,相对先找不到路径的一定是放在相对后面,所以当前搜索的起点from会插在当前输出路径的第一个位置。

// No.332 重新安排行程
type pair struct {
	// pair储存机票目的地和当前航线是否已经使用
	target  string
	visited bool
}

// 储存pair数组,实现sort接口
type pairs []*pair

func (p pairs) Len() int {
	return len(p)
}

func (p pairs) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func (p pairs) Less(i, j int) bool {
	return p[i].target < p[j].target
}

func findItinerary(tickets [][]string) (res []string) {
	// record储存每个机场可到达的目的地,以及当前航线是否已选择
	targets := make(map[string]pairs, 0)
	for _, ticket := range tickets {
		if targets[ticket[0]] == nil {
			targets[ticket[0]] = make(pairs, 0)
		}
		// 添加新的可达目的地,初始置为未选择
		targets[ticket[0]] = append(targets[ticket[0]], &pair{target: ticket[1], visited: false})
	}
	for k := range targets {
		// 按字典升序排序目的地,保证第一个选出的就是字典序最小的结果
		sort.Sort(targets[k])
	}
	var backtrack func() bool
	backtrack = func() bool {
		if len(tickets)+1 == len(res) {
			// 结果机场数量比票数大1说明已经构建出所有路径,找到了结果
			return true
		}
		// 当前所在机场
		here := res[len(res)-1]
		for i, t := range targets[here] {
			if i > 0 && targets[here][i-1].target == t.target && !targets[here][i-1].visited {
				// 剪枝(非常重要),如果上一个目的地和当前的相同,且上一个没用过,说明是从上一个回溯回来的
				// 上一个不可能那么当前的也不可能,直接跳过
				continue
			}
			// 枚举所有可能的目的地,已经使用过的航线除外
			if !t.visited {
				res = append(res, t.target)
				t.visited = true
				if backtrack() {
					return true
				}
				res = res[:len(res)-1]
				t.visited = false
			}
		}
		return false
	}
	// 所有机票从JFK出发
	res = append(res, "JFK")
	backtrack()
	return
}

2.N皇后

在这里插入图片描述

var (
	res  [][]string
	path [][]int
)

func solveNQueens(n int) [][]string {
	res = make([][]string, 0)
	path = make([][]int, n)
	for i := 0; i < n; i++ {
		path[i] = make([]int, n)
	}
	dfs(n, 0)
	return res
}

func dfs(n int, curRow int) {
	if curRow == n {
		temp := make([]string, 0)
		for i := 0; i < n; i++ {
			str := ""
			for j := 0; j < n; j++ {
				if path[i][j] == 0 {
					str = str + "."
				} else {
					str = str + "Q"
				}
			}
			temp = append(temp, str)
		}
		res = append(res, temp)
	}
	for i := 0; i < n; i++ {
		if canPlaceQueen(curRow, i, n) {
			path[curRow][i] = 1
			dfs(n, curRow+1)
			path[curRow][i] = 0
		}
	}
}

func canPlaceQueen(row, col, n int) bool {
	if row >= n || col >= n || row < 0 || col < 0 {
		return false
	}
	// 检查同行同列的情况
	for i := 0; i < n; i++ {
		if path[i][col] == 1 {
			return false
		}
		if path[row][i] == 1 {
			return false
		}
	}
	// 检查主对角线
	row1, col1 := row, col
	for row1 >= 0 && col1 >= 0 {
		if path[row1][col1] == 1 {
			return false
		}
		row1--
		col1--
	}
	row1, col1 = row, col
	for row1 < n && col1 < n {
		if path[row1][col1] == 1 {
			return false
		}
		row1++
		col1++
	}
	// 检查副对角线
	row1, col1 = row, col
	for row1 >= 0 && col1 < n {
		if path[row1][col1] == 1 {
			return false
		}
		row1--
		col1++
	}
	row1, col1 = row, col
	for row1 < n && col1 >= 0 {
		if path[row1][col1] == 1 {
			return false
		}
		row1++
		col1--
	}
	return true
}

3.解数独

在这里插入图片描述

var (
	chunks     [9][]bool
	rows       [9][]bool
	cols       [9][]bool
	matrixSize int  = 9
	emptyCount int  = 0
	hasFind    bool = false
)

func solveSudoku(board [][]byte) {
	emptyCount = 0
	hasFind = false
	for i := 0; i < matrixSize; i++ {
		chunks[i] = make([]bool, 10) //用来表示每个区域中的数字1-9是否已经被使用
		rows[i] = make([]bool, 10)   //用来表示每行中的数字1-9是否已经被使用
		cols[i] = make([]bool, 10)   //用来表示每列中的数字1-9是否已经被使用
	}
	for i := 0; i < matrixSize; i++ {
		for j := 0; j < matrixSize; j++ {
			if board[i][j] != '.' {
				num := board[i][j] - '0'
				chunkId := findChunkIndex(i, j)
				chunks[chunkId][num] = true
				rows[i][num] = true
				cols[j][num] = true
			} else {
				emptyCount++
			}
		}
	}
	dfs(emptyCount, board, &hasFind)
}

func dfs(emptyCount int, board [][]byte, hasFind *bool) {
	if *hasFind { //在其他分支已经找到答案了
		return
	}
	if emptyCount == 0 { //空格全部填完,找到答案
		*hasFind = true
		return
	}
	for i := 0; i < matrixSize; i++ {
		for j := 0; j < matrixSize; j++ {
			if board[i][j] == '.' {
				for num := byte(1); num <= 9; num++ {
					if canPlaceNumber(i, j, num) {
						chunkId := findChunkIndex(i, j)
						board[i][j] = '0' + num
						chunks[chunkId][num] = true
						rows[i][num] = true
						cols[j][num] = true
						emptyCount--
						dfs(emptyCount, board, hasFind)
						if *hasFind { //在其他分支已经找到答案了
							return
						}
						chunks[chunkId][num] = false
						rows[i][num] = false
						cols[j][num] = false
						board[i][j] = '.'
						emptyCount++
					}
				}
				return
			}
		}
	}
}
//查看在该位置是否能放下该数
func canPlaceNumber(row, col int, num byte) bool {
	//行列中是否已经有这个数
	if rows[row][num] || cols[col][num] {
		return false
	}
	//3*3的块中是否有这个数
	if chunks[findChunkIndex(row, col)][num] {
		return false
	}
	return true
}
//找到所属的3*3的块
func findChunkIndex(row, col int) int {
	return (row/3)*3 + col/3
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/665082.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

我与C++的爱恋:vector的使用

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;我与C的爱恋 ​ 文章目录 一、vector的简单介绍二、vector的使用构造函数遍历容器对容器的操作vector 的增删查改 一、vector的简单介绍 vector是表示可变大小数组的序列容器 就像数组…

并查集拓展(扩展域并查集)

事实证明&#xff0c;扩展域并查集应该在带权并查集前面讲的&#xff0c;因为比较好理解&#xff0c;而且回过头看带权并查集可能也会更轻松一些。 https://www.luogu.com.cn/problem/P1892https://www.luogu.com.cn/problem/P1892 题目描述 现在有 &#x1d45b; 个人&…

VBA语言専攻每周通知20240531

通知20240531 各位学员∶本周MF系列VBA技术资料增加616-620讲&#xff0c;T3学员看到通知后请免费领取,领取时间5月31日晚上19:00-6月1日晚上20:00。本次增加内容&#xff1a; MF616:创建具有间隔的计时器循环 MF617:计时器的计时与重置 MF618:列出单字符所有可能的排列组合…

怎么把图片大小调小?在线改图片大小的方法

怎么把比较大的图片压缩变小呢&#xff1f;在使用图片的时候&#xff0c;比较常见的一个问题就是图片太大导致无法正常上传&#xff0c;需要将图片处理到合适的大小之后&#xff0c;才可以正常在网上上传。现在一般调整图片大小多会通过使用在线改图片大小的在线工具来处理&…

动态路由协议实验——RIP

动态路由协议实验——RIP 什么是RIP ​ RIP(Routing Information Protocol,路由信息协议&#xff09;是一种内部网关协议&#xff08;IGP&#xff09;&#xff0c;是一种动态路由选择协议&#xff0c;用于自治系统&#xff08;AS&#xff09;内的路由信息的传递。RIP协议基于…

Codigger编码场景介绍(三):调试场景(Debug Scenery)

Codigger&#xff0c;一个专为开发人员设计的工具&#xff0c;致力于为不同的开发场景提供最佳的切换体验。Codigger囊括了多种场景&#xff0c;如传统场景、调试场景、设计器场景、驾驶舱场景以及纯净场景等。在上一篇文章中&#xff0c;我们介绍了驾驶舱场景&#xff0c;今天…

SpringBoot集成JOOQ加Mybatis-plus使用@Slf4j日志

遇到个问题记录下&#xff0c;就是SpringBoot使用Mybatis和Mybatis-plus时可以正常打印日志&#xff0c;但是JOOQ的操作日志确打印不出来&#xff1f; 下面的解决方法就是将JOOQ的日志单独配置出来&#xff0c;直接给你们配置吧&#xff01; 在项目的resources目录下创建日志…

windows11下将Labelme标注数据转为YOLOV5训练数据集

完整代码&#xff1a; import shutil import os import numpy as np import json from glob import glob import cv2 from sklearn.model_selection import train_test_split from utils.data_dir import root_dirdef convert(size, box):dw 1. / (size[0])dh 1. / (size[1]…

mysql大表的深度分页慢sql案例(跳页分页)-2

1 背景 有一张大表&#xff0c;内容是费用明细表&#xff0c;数据量约700万级&#xff0c; 普通B树索引KEY idx_fk_fymx_qybh_xfsj (qybh,xfsj)。 1.1 原始深度分页sql select t.* from fk_fymx t where t.qybh XXXXXXX limit 100000,100; 深度分页会导致加载数据行过多1000001…

详细解析Barlow Twins:自监督学习中的创新方法

首先先简单了解一下机器学习中&#xff0c;主要有三种学习范式&#xff1a;监督学习、无监督学习和自监督学习&#xff1a; 监督学习&#xff1a;依赖带标签的数据&#xff0c;通过输入输出映射关系进行训练。无监督学习&#xff1a;不依赖标签&#xff0c;关注数据的内在结构…

整合Spring Boot 框架集成Knife4j

本次示例使用Spring Boot作为脚手架来快速集成Knife4j,Spring Boot版本2.3.5.RELEASE ,Knife4j版本2.0.7 POM.XML完整文件代码如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0…

美创CTO周杰受邀参加2024省级现代服务业高研班,分享“人工智能数据安全与防护技术”

近日&#xff0c;为期三天的省级现代服务业“模型生态应用与安全治理”高级研修班在杭州成功举办。 本次高研班由浙江省人社厅、浙江省委网信办指导&#xff0c;浙江省网络空间安全协会主办&#xff0c;旨在抢抓新一轮人工智能带来的科技革命与产业变革新机遇&#xff0c;助推浙…

C++入门——类和对象【3】(6)

前言 本节是C类和对象中的最后一节&#xff0c;学完本节内容并且能够掌握之前所学的所有内容的话&#xff0c;C就可以说是入门了&#xff0c;那我们废话不多说&#xff0c;正式进入今天的学习 1. 再谈构造函数 1.1 引入 我们在栈的背景下来看 栈的代码&#xff1a; ​type…

Docker Hub 国内镜像源配置

Docker Hub 国内镜像源配置 Docker Hub 国内镜像源是指在国内境内提供 Docker 镜像服务的镜像源。由于国际网络带宽等问题&#xff0c;国内用户下载 Docker 镜像通常速度较慢。因此&#xff0c;为了解决这个问题&#xff0c;一些国内的公司和组织提供了 Docker 镜像的国内镜像…

什么是机器人离线编程? 衡祖仿真

一、什么是机器人离线编程&#xff1f; 机器人离线编程是自动化生产的重要一环。离线编程指&#xff0c;在建立了机器人的三维模拟场景后&#xff0c;经由软件仿真计算&#xff0c;生成控制机器人运动轨迹&#xff0c;进而生成机器人的控制指令。工程师可以由此来控制物理环境…

基于SSM框架的手机商城项目

后端: 订单管理 客户管理&#xff1a; 商品管理 类目管理 前端&#xff1a; 首页&#xff1a;

算法(十一)贪婪算法

文章目录 算法简介算法概念算法举例 经典问题 -背包问题 算法简介 算法概念 贪婪算法&#xff08;Greedy&#xff09;是一种在每一步都采取当前状态下最好的或者最优的选择&#xff0c;从而希望导致结果也是全局最好或者最优的算法。贪婪算法是当下局部的最优判断&#xff0c…

java向上转型

介绍 代码 父类 package b;public class father_ {//father classString name"动物";int age10;public void sleep() {System.out.println("睡");}public void run() {System.out.println("跑");}public void eat() {System.out.println("…

案例|开发一个美业小程序,都有什么功能

随着移动互联网的迅猛发展&#xff0c;美业连锁机构纷纷寻求数字化转型&#xff0c;以小程序为载体&#xff0c;提升服务效率&#xff0c;增强客户体验。 线下店现在面临的困境&#xff1a; 客户到店排队时间过长&#xff0c;体验感受差 新客引流难&#xff0c;老用户回头客…

实验---DC-AC逆变器(1)---EG8010+NSI6602驱动IGBT实验

一、设计电路 1.LCC 主回路模块原理图 1.1 电源部分 这个电源部分电路图是一个简单而有效的DC-DC转换器设计&#xff0c;包含输入保护和滤波、电源模块、以及输出滤波和稳定。 a. 输入电源部分 输入电源 (E12V): 电路从E12V端子接收12V的直流电源。这是整个电路的输入电源。…