题目:
矩阵中的的点1代表陆地,0代表海洋,求两个由1组成的岛之间的最短路径,规定只能走上下左右,不能斜着走,求联通两个岛的最短路径
分析:
1 要探清岛的边界,从每一个节点是1的位置开始,上下左右移动知道找到边界0
2 从岛边界第一个0开始,往外依次标记距离
3 实现上可以将二维压缩成一维
代码:
package main
import (
"fmt"
// "sync"
)
//当前位置发现了1,就把这一片的1全部拿取,遇到0就停,实际上形成了一个小岛
// m二维数组,i,j 二维index,N二维行总数,M二维列总数,curs当前为1的而二维坐标压缩成一维后的index、records二维压缩为一维
//main函数控制了从[i][j]==1开始查找岛的边界,一轮相当于完成一个岛的边界探寻,
//保证传入的curs和tmp是不同的数组,底层指针是不一样的
//
func reflcet(m [][]int, N,M,i,j int,curs *[]int,tmp *[]int,index int) int{
// fmt.Printf("ref icurs=============%v\n",curs)
// fmt.Printf("ref tmp=============%v\n",tmp)
// fmt.Printf("address of slice %p add of Arr %p\n", &curs, &tmp)
if i<0 || j<0 || i==N || j==M || m[i][j]!=1{
return index
}
m[i][j]=2
idx:=i*M+j
(*tmp)[idx]=1//对tmp地址上的这个index操作,一定要用括号外面括起来
// fmt.Printf("after label tmp=============%v\n",tmp)
(*curs)[index]=idx
index++
// fmt.Printf("after label icurs=============%v\n",curs)
// fmt.Printf("after label slice %p add of Arr %p\n", &curs, &tmp)
index=reflcet(m,N,M,i-1,j,curs,tmp,index)
index=reflcet(m,N,M,i+1,j,curs,tmp,index)
index=reflcet(m,N,M,i,j-1,curs,tmp,index)
index=reflcet(m,N,M,i,j+1,curs,tmp,index)
return index
}
//
//宽度优先遍历curs里面的点,从curs里面拿到index,再从tmp[1,0,1]里面找到对应在二维的上下左右==0的点,再在tmp找到映射把它标为广播的距离v
//next 下一次广播的队列[],v当前广播的距离1,2,3 ,size就是上面得到的curs的有效数值长度
// queuesize=bfs(m , N,M,v ,queuesize,curs,tmp,next)
func bfs(m [][]int, N,M,v ,size int,curs,tmp,next []int) int{
// var once sync.Once
fmt.Printf("curs=============%v\n",curs)
// fmt.Printf("curs=============%v\n",next)
fmt.Printf("vvvvvvvv=============%v\n",v)
//next记录了每一轮要标记的上下左右共有多少个点,
//因为下面使用的时候开始就是++,如果初始为0的时候就是从1开始,这样记录next的时候就会直接从1开始,把index=0算在内
//因此直接初始为-1,上下左右谁先对它++是无法确定的,不管谁先开始,++就变成了0,这样就解决了每次把0算在内的问题
//最后return的时候-1就不会越界
nexti:=-1
//从哪些点扩散,从curs的坐标,长度就是size,标记完这些点返回
for i:=0;i<size;i++{
// fmt.Printf("curs[i]=============%v\n",curs[i])
//将一维的的点映射到二维再映射到一维,找到二维上下左右的的爱你对应的一维的坐标
//确定二维对应的边界,再映射到一维
up:=0
if curs[i]<M{
up=-1
}else{
up=curs[i]-M
}
down:=0
if curs[i]+M>=N*M{
down=-1
}else{
down=curs[i]+M
}
left:=0
if curs[i]%M==0{
left=-1
}else{
left=curs[i]-1
}
right:=0
if curs[i]%M==M-1{
right=-1
}else{
right=curs[i]+1
}
//这些点是0才扩散,不是0就是已经标记过了的点
if up!=-1 && tmp[up]==0{
//注意++一定是满足标记条件才累加
tmp[up]=v
nexti++
next[nexti]=up
}
if down!=-1 && tmp[down]==0{
nexti++
tmp[down]=v
next[nexti]=down
}
if left!=-1 && tmp[left]==0{
nexti++
tmp[left]=v
next[nexti]=left
}
if right!=-1 && tmp[right]==0{
nexti++
tmp[right]=v
next[nexti]=right
}
}
// fmt.Printf("records =============%v\n",tmp)
// fmt.Printf("next =============%v\n",next)
// fmt.Printf("nextiiiiiiiii =============%v\n",nexti)
//返回下一次要标记的点的长度
return nexti+1
}
func main(){
var m [][]int
t1:=[]int{1,1,1,0,0}
t2:=[]int{1,0,1,0,0}
t3:=[]int{1,0,1,1,0}
t4:=[]int{0,1,1,0,0}
t5:=[]int{0,1,0,0,1}
t6:=[]int{0,0,0,0,1}
t7:=[]int{0,0,0,1,1}
m=append(m,t1)
m=append(m,t2)
m=append(m,t3)
m=append(m,t4)
m=append(m,t5)
m=append(m,t6)
m=append(m,t7)
fmt.Println(m)
N:=len(m)
M:=len(m[0])
for i:=0;i<N;i++{
fmt.Println(m[i])
}
//每个数组的都是独立的变量,不能引用
curs:=[]int{}
records:=[][]int{}
tmp:=[]int{}
next:=[]int{}
for i :=0;i<N*M;i++{
curs=append(curs,0)
tmp=append(tmp,0)
next=append(next,0)
}
queuesize:=0
for i:=0;i<N;i++{
for j:=0;j<M;j++{
if m[i][j]==1{
//queuesize:要标记的长度
queuesize=reflcet(m,N,M,i,j,&curs,&tmp,0)
v:=1
//循环标记距离,找到curs中的点对应在records中的位置,从他开始找到它的上下左右的点,标记完返回下一次要标记的点的队列长度
for queuesize !=0{
v++
//queuesize:每标记完一轮记录下一轮要标记的长度,等于0就退出,表示标记完成
queuesize=bfs(m , N,M,v ,queuesize,curs,tmp,next)
var temp []int
//交换curs和next,
temp=curs
curs=next
next=temp
}
//record是一个二维数组,以行代表一个岛的辐射距离,将计算好距离的数组添加到records
records=append(records,tmp)
//然后将tmp,cues,naxt分别置空,注意一定是三个数组底层地址是不一样的
temp:=[]int{}
temp1:=[]int{}
temp2:=[]int{}
for i :=0;i<N*M;i++{
temp=append(temp,0)
temp1=append(temp1,0)
temp2=append(temp2,0)
}
tmp=temp
curs=temp1
next=temp2
}
}
}
fmt.Println(records)
shortestway:=records[0][0]+records[1][0]
for i:=1;i<N*M;i++{
tmp:=records[0][i]+records[1][i]
if tmp<shortestway{
shortestway=tmp
}
}
fmt.Println(shortestway)
}
总结:
1每个数组都有自己的作用,并且是独立的,一个数组不能指向任何另外一个数组
2,标记距离函数山下左右谁先第一个是无法判断的,当next值初始为0的时候++就从1开始,导致0永远算作了下一轮要标记的对象,占了容量而队尾的对象就被忽略了