2022-05-17:在一个地图上有若干个炸弹,每个炸弹会呈现十字型引爆。 每个炸弹都有其当量值,这个值决定了这个炸弹的爆炸半径。 如果一个炸弹被引爆时,有其它炸弹在其爆炸半径内,那么其它炸弹也会爆炸

2022-05-17:在一个地图上有若干个炸弹,每个炸弹会呈现十字型引爆。
每个炸弹都有其当量值,这个值决定了这个炸弹的爆炸半径。
如果一个炸弹被引爆时,有其它炸弹在其爆炸半径内,那么其它炸弹也会爆炸。
请问使地图上所有炸弹爆炸所需的最少人为引爆次数。
例如:
0,0,0,0,0
0,0,0,1,0
0,0,0,0,0
上图中val为1的单元是一个炸弹,人为引爆后地图变成下面的样子:
0, 0, 0,-1, 0
0, 0,-1,-1,-1
0, 0, 0,-1, 0
题目并没有给数据量,面经题目的通病。
来自亚马逊。

答案2022-05-17:

并查集不对。
贪心最大当量不对。
贪心最多不对。
有序表 + 强连通分量。

代码用golang编写。代码如下:

package main

import (
	"fmt"
	"sort"
)

func main() {
	map0 := [][]int{
		{0, 0, 2, 0, 2},
		{1, 0, 0, 0, 0},
		{0, 0, 1, 0, 2},
		{0, 0, 1, 0, 0},
		{0, 0, 1, 0, 0},
	}
	ans := minBombs2(map0)
	fmt.Println(ans)
}

// 正式方法
// 用到有序表 + 强连通分量
func minBombs2(map0 [][]int) int {
	n := len(map0)
	rowTreeMaps := make([]map[int]int, 0)
	rowTreeMapsi := make([][]int, 0)
	colTreeMaps := make([]map[int]int, 0)
	colTreeMapsi := make([][]int, 0)
	for i := 0; i < n; i++ {
		rowTreeMaps = append(rowTreeMaps, make(map[int]int))
		rowTreeMapsi = append(rowTreeMapsi, make([]int, 0))
		colTreeMaps = append(colTreeMaps, make(map[int]int))
		colTreeMapsi = append(colTreeMapsi, make([]int, 0))
	}
	m := 0
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			if map0[i][j] != 0 {
				m++
				rowTreeMaps[i][j] = m
				rowTreeMapsi[i] = append(rowTreeMapsi[i], j)
				colTreeMaps[j][i] = m
				colTreeMapsi[j] = append(colTreeMapsi[j], i)
			}
		}
	}
	for i := 0; i < n; i++ {
		sort.Ints(rowTreeMapsi[i])
		sort.Ints(colTreeMapsi[i])
	}
	edges := make([][]int, 0)
	for i := 0; i <= m; i++ {
		edges = append(edges, make([]int, 0))
	}
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			if map0[i][j] != 0 {
				rowTreeMap := rowTreeMaps[i]
				rowTreeMapi := rowTreeMapsi[i]
				colTreeMap := colTreeMaps[j]
				colTreeMapi := colTreeMapsi[j]
				from := rowTreeMap[j]
				col := j - 1
				for floorKey(rowTreeMapi, col) != -1 && j-rowTreeMapi[floorKey(rowTreeMapi, col)] <= map0[i][j] {
					col = rowTreeMapi[floorKey(rowTreeMapi, col)]
					edges[from] = append(edges[from], rowTreeMap[col])
					col--
				}
				col = j + 1
				for ceilingKey(rowTreeMapi, col) != -1 && rowTreeMapi[ceilingKey(rowTreeMapi, col)]-j <= map0[i][j] {
					col = rowTreeMapi[ceilingKey(rowTreeMapi, col)]
					edges[from] = append(edges[from], rowTreeMap[col])
					col++
				}
				row := i - 1
				for floorKey(colTreeMapi, row) != -1 && i-colTreeMapi[floorKey(colTreeMapi, row)] <= map0[i][j] {
					row = colTreeMapi[floorKey(colTreeMapi, row)]
					edges[from] = append(edges[from], colTreeMap[row])
					row--
				}
				row = i + 1
				for ceilingKey(colTreeMapi, row) != -1 && colTreeMapi[ceilingKey(colTreeMapi, row)]-i <= map0[i][j] {
					row = colTreeMapi[ceilingKey(colTreeMapi, row)]
					edges[from] = append(edges[from], colTreeMap[row])
					row++
				}
			}
		}
	}
	scc := NewStronglyConnectedComponents(edges)
	sccn := scc.getSccn()
	in := make([]int, sccn+1)
	out := make([]int, sccn+1)
	dag := scc.getShortGraph()
	for i := 1; i <= sccn; i++ {
		for _, j := range dag[i] {
			out[i]++
			in[j]++
		}
	}
	zeroIn := 0
	for i := 1; i <= sccn; i++ {
		if in[i] == 0 {
			zeroIn++
		}
	}
	return zeroIn
}

// 在arr上,找满足>=value的最左位置
func ceilingKey(arr []int, v int) int {
	L := 0
	R := len(arr) - 1
	index := -1 // 记录最左的对号
	for L <= R {
		mid := L + (R-L)>>1
		if arr[mid] >= v {
			index = mid
			R = mid - 1
		} else {
			L = mid + 1
		}
	}
	return index
}

// 在arr上,找满足<=value的最右位置
func floorKey(arr []int, v int) int {
	L := 0
	R := len(arr) - 1
	index := -1 // 记录最右的对号
	for L <= R {
		mid := L + (R-L)>>1
		if arr[mid] <= v {
			index = mid
			L = mid + 1
		} else {
			R = mid - 1
		}
	}
	return index
}

type StronglyConnectedComponents struct {
	nexts     [][]int
	n         int
	stack     []int
	stackSize int
	dfn       []int
	low       []int
	cnt       int
	scc       []int
	sccn      int
}

// 请保证点的编号从1开始,不从0开始
// 注意:
// 如果edges里有0、1、2...n这些点,那么容器edges的大小为n+1
// 但是0点是弃而不用的,所以1..n才是有效的点,所以有效大小是n
func NewStronglyConnectedComponents(edges [][]int) *StronglyConnectedComponents {
	ans := &StronglyConnectedComponents{}
	ans.nexts = edges
	ans.init()
	ans.scc0()
	return ans
}

func (this *StronglyConnectedComponents) init() {
	this.n = len(this.nexts)
	this.stack = make([]int, this.n)
	this.stackSize = 0
	this.dfn = make([]int, this.n)
	this.low = make([]int, this.n)
	this.cnt = 0
	this.scc = make([]int, this.n)
	this.sccn = 0
	this.n--
}

func (this *StronglyConnectedComponents) scc0() {
	for i := 1; i <= this.n; i++ {
		if this.dfn[i] == 0 {
			this.tarjan(i)
		}
	}
}

func (this *StronglyConnectedComponents) tarjan(p int) {
	this.cnt++
	this.dfn[p] = this.cnt
	this.low[p] = this.cnt
	this.stack[this.stackSize] = p
	this.stackSize++
	for _, q := range this.nexts[p] {
		if this.dfn[q] == 0 {
			this.tarjan(q)
		}
		if this.scc[q] == 0 {
			if this.low[p] > this.low[q] {
				this.low[p] = this.low[q]
			}
		}
	}
	if this.low[p] == this.dfn[p] {
		this.sccn++
		top := 0
		for {
			this.stackSize--
			top = this.stack[this.stackSize]
			this.scc[top] = this.sccn
			if top == p {
				break
			}
		}
	}
}

func (this *StronglyConnectedComponents) getScc() []int {
	return this.scc
}

func (this *StronglyConnectedComponents) getSccn() int {
	return this.sccn
}

func (this *StronglyConnectedComponents) getShortGraph() [][]int {
	shortGraph := make([][]int, 0)
	for i := 0; i <= this.sccn; i++ {
		shortGraph = append(shortGraph, make([]int, 0))
	}
	for u := 1; u <= this.n; u++ {
		for _, v := range this.nexts[u] {
			if this.scc[u] != this.scc[v] {
				shortGraph[this.scc[u]] = append(shortGraph[this.scc[u]], this.scc[v])
			}
		}
	}
	return shortGraph
}

执行结果如下:

在这里插入图片描述


左神java代码

posted @ 2022-05-17 19:33  福大大架构师每日一题  阅读(16)  评论(0编辑  收藏  举报  来源