算法61天|图论

Posted 圆圆圈圈扁扁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法61天|图论相关的知识,希望对你有一定的参考价值。

leetcode-master/图论广索理论基础.md at master · youngyangyang04/leetcode-master · GitHub

leetcode-master/图论深搜理论基础.md at master · youngyangyang04/leetcode-master · GitHub

力扣

1791. 找出星型图的中心节点   

var findCenter = function(edges) 
    const n = edges.length + 1;
    const degree = new Array(n+1).fill(0)
    for(const edge of edges)
        degree[edge[0]]++
        degree[edge[1]]++
    
    for(let i = 0;;i++)
        if(degree[i] === n-1)
            return i
        
    
;

统计各个节点的度,使用数组的方法统计,将节点的值当作数组的索引。然后有多一个的话,就++。会发现中间节点的度是n-1,其它的节点的度是1 

tleetcode-master/1791.找出星型图的中心节点.md at master · youngyangyang04/leetcode-master · GitHub
797. 所有可能的路径 

var allPathsSourceTarget = function(graph) 
    let result = []
    let path = []
    //x 是当前遍历的节点
    // graph 是存当前的图
    const dfs = function(path,graph,x)
        // 终止条件
        if(x === graph.length - 1)
            //将结果加入
            result.push([...path])
            return
        
        for(let i = 0;i<graph[x].length;i++)
            //将节点加入
            path.push(graph[x][i])
            //dfs
            dfs(path,graph,graph[x][i])
            // 回溯
            path.pop()
        
    
    path.push(0)
    dfs(path,graph,0)
    return result
;

力扣
200. 岛屿数量 

dfs

var numIslands = function (grid) 
    // 使用dfs
    let dirx = [-1, 1, 0, 0]
    let diry = [0, 0, -1, 1]
    let row = grid.length
    let col = grid[0].length

    const dfs = function (grid, visited, i, j) 
        //终止条件
        //for循环
        for (let k = 0; k < 4; k++) 
            let x = i + dirx[k]
            let y = j + diry[k]
            if (x >= row || y >= col || x < 0 || y < 0) 
                continue
            
            if (visited[x][y] === false && grid[x][y] === '1') 
                visited[x][y] = true
                dfs(grid, visited, x, y)
            
        
    
    let visited = new Array(grid.length).fill(false).map(() => new Array(grid[0].length).fill(false))
    let count = 0
    for (let i = 0; i < row; i++) 
        for (let j = 0; j < col; j++) 
            if (visited[i][j] === false && grid[i][j] === '1') 
                visited[i][j] === true
                count++;
                dfs(grid, visited, i, j)
            

        
    

    return count
;

 BFS

var numIslands = function (grid) 
    let dirx = [-1, 1, 0, 0]
    let diry = [0, 0, -1, 1]
    let row = grid.length
    let col = grid[0].length
    let visited = new Array(row).fill(false).map(() => new Array(col).fill(false))
        // 先将节点加入队列中
    const bfs = function (grid,visited,i,j) 
        let que = []
        que.push([i, j])
        visited[i][j] = true
        while (que.length > 0) 
            // 弹出当前节点,获取当前元素的坐标
            const [curx, cury] = que.shift()
            //判断它上下左右有没有岛屿
            for (let k = 0; k < 4; k++) 
                let x = curx + dirx[k]
                let y = cury + diry[k]
                if (x < 0 || y < 0 || x >= row || y >= col) continue
                if (visited[x][y] != true && grid[x][y] === '1') 
                    visited[x][y] = true
                    //加入节点
                    que.push([x, y])
                
            
        
    
    let count = 0
    for(let i = 0;i<row;i++)
        for(let j = 0;j<col;j++)
            if(visited[i][j] === false && grid[i][j] === '1')
                count ++;
                bfs(grid,visited,i,j)
            
        
    
    return count

;


463. 岛屿的周长 

如果碰到水域的话就+1,如果碰到边界也加1

var islandPerimeter = function(grid) 
    let row = grid.length
    let col = grid[0].length
    // i-1,j/i+1,j/i,j-1/i,j+1
    let dirx = [-1,1,0,0]
    let diry = [0,0,-1,1]
    let count = 0
    for(let i = 0;i<row;i++)
        for(let j =0;j<col;j++)
            if(grid[i][j] === 1)
                for(let k=0;k<4;k++)
                    let x = i + dirx[k]
                    let y = j + diry[k]
                    if(x >= row || 
                        y >= col||
                        x < 0||
                        y<0||
                        grid[x][y] === 0)
                            count ++;
                        
                
                // 判断上下左右,如果遇到水域+1,如果遇到边界就+1
            

        
    
    return count 
    
;


695. 岛屿的最大面积 

BFS

var maxAreaOfIsland = function (grid) 
    const bfs = function (grid, i, j, visited,count) 
        const dirx = [-1, 1, 0, 0]
        const diry = [0, 0, -1, 1]
        let que = []
        visited[i][j] = true
        que.push([i, j])
        count ++
        while (que.length > 0) 
            const [curx, cury] = que.shift()
            for (let k = 0; k < 4; k++) 
                let newx = curx + dirx[k]
                let newy = cury + diry[k]
                if (newx < 0 || newy < 0|| newx >= row || newy >= col) continue
                if (grid[newx][newy] === 1 && visited[newx][newy] !== true) 
                    visited[newx][newy] = true
                    que.push([newx,newy])
                    count ++
                
            
        
        return count
    
    // 找到岛屿,找到的话,就数统计个数
    let result = 0
    // bfs
    const col = grid[0].length
    const row = grid.length
    let visited = new Array(row).fill(false).map(() => new Array(col).fill(false))
    for (let i = 0; i < row; i++) 
        for (let j = 0; j < col; j++) 
            if (visited[i][j] === false && grid[i][j] === 1) 
                let count = 0
                count = bfs(grid, i, j, visited,count)
                result = Math.max(result,count)
            
        
    
    return result
;

dfs 

var maxAreaOfIsland = function(grid) 
    // This function uses depth-first search algorithm to traverse the binary matrix grid.
    const dfs = function(grid,i,j,visited)
        const dirx = [-1,1,0,0]
        const diry = [0,0,-1,1]
        visited[i][j] = true
        let area = 1
        for(let k= 0;k<4;k++)
            let curx = dirx[k] + i
            let cury = diry[k] + j
            if(curx < 0 || cury <0 || curx >= row || cury >=col) continue
            if(visited[curx][cury] === false && grid[curx][cury] === 1)
                visited[curx][cury] = true
                area += dfs(grid,curx,cury,visited)
            
        
        return area
    
    const row = grid.length
    const col = grid[0].length
    let result = 0
    let visited = new Array(row).fill(false).map(()=>new Array(col).fill(false))
    for(let i = 0;i<row;i++)
        for(let j = 0;j<col;j++)
            if(visited[i][j] === false && grid[i][j] === 1)
                result = Math.max(dfs(grid,i,j,visited),result)
            
        
    
    return result  
;


827. 最大人工岛(hard) 
1020. 飞地的数量  (medium)

var numEnclaves = function(grid) 
    //bfs
    const bfs = function(grid,i,j,visited,count)
        let que = []
        const dirx = [-1,1,0,0]
        const diry = [0,0,-1,1]
        que.push([i,j])
        count ++ 
        visited[i][j] = true
        while(que.length > 0)
            const [x,y] = que.shift()
            for(let k = 0;k<4;k++)
                let curx = x + dirx[k]
                let cury = y + diry[k]
                if(curx < 0 || cury < 0|| curx>=row || cury >= col) continue
                if(visited[curx][cury] === false && grid[curx][cury] === 1)
                    que.push([curx,cury])
                    count ++
                    visited[curx][cury] = true
                
            
        
        return count
    
    const row = grid.length
    const col = grid[0].length
    let result = 0
    let visited = new Array(row).fill(false).map(()=>new Array(col).fill(false))
    for(let i = 0;i<row;i++)
        if(visited[i][0] === false && grid[i][0] === 1)
            bfs(grid,i,0,visited)
        
        if(visited[i][col-1] === false && grid[i][col-1] === 1)
             bfs(grid,i,col-1,visited)
        
    
    for(let i = 0;i<col;i++)
        if(visited[0][i] === false && grid[0][i] === 1)
            bfs(grid,0,i,visited)
        
        if(visited[row-1][i] === false && grid[row-1][i] === 1)
            bfs(grid,row-1,i,visited)
        
    
    for(let i = 0;i<row;i++)
        for(let j = 0;j<col;j++)
            if(visited[i][j] === false && grid[i][j] === 1)
                let count = 0
                count = bfs(grid,i,j,visited,count)
                result += count
            
        
    
    return result
;

这道题是先把边界的东西全部转化为true,但是并不需要给他计数。
130. 被围绕的区域 

var solve = function(board) 
    const bfs = function(board,i,j)
        const dirx = [-1,1,0,0]
        const diry = [0,0,-1,1]
        let que = []
        que.push([i,j])
        board[i][j] = "A" 
        while(que.length>0)
            let [x,y] = que.shift()
            for(let k = 0;k<4;k++)
                let curx = dirx[k]+x
                let cury = diry[k]+y
                if(curx<0||cury<0||curx>=row||cury>=col) continue
                if( board[curx][cury] === "O")
                    que.push([curx,cury])
                    board[curx][cury] = "A" 
                
            
        
    
    const row = board.length
    const col = board[0].length
    let visited = new Array(row).fill(false).map(()=>new Array(col).fill(false))
    // 把边缘的都从O转化为了A
    for(let i = 0;i<row;i++)
        if(board[i][0] === "O") bfs(board,i,0)
        if(board[i][col-1] === "O") bfs(board,i,col-1)  
    
    console.log(board)
    for(let i = 0;i<col;i++)
        if(board[0][i] === "O") 
            bfs(board,0,i)
        
        if(board[row-1][i] === "O") 
            bfs(board,row-1,i)
        
        
    
    console.log(board)
    for(let i = 0;i<row;i++)
        for(let j = 0;j<col;j++)
            if(board[i][j] === "O")
                board[i][j] = "X"
            
            if(board[i][j] === "A")
                board[i][j] = "O"
            
        
    
    return board
;

 这道题和飞地数量那道题一样的思路。需要注意的地方是,我们需要多次访问数组中的值,所以我们不能使用visited来标记,不然的话没有办法再遍历一次。

需要先把边缘的岛屿转化为A,然后第二部再遍历一次,如果遇到A就转化为O,如果遇到O就转化为A。

这些题都好容易写错,写=== 的时候很容易写成=

var solve = function (board) 
    const dfs = function (board, i, j) 
        const dirx = [-1, 1, 0, 0]
        const diry = [0, 0, -1, 1]
        board[i][j] = "A"
        for (let k = 0; k < 4; k++) 
            let curx = dirx[k] + i
            let cury = diry[k] + j
            if (curx < 0 || cury < 0 || curx >= row || cury >= col)  continue 
            if (board[curx][cury] === "O") 
                board[curx][cury] = "A"
                dfs(board, curx, cury)
            
        
    
const row = board.length
const col = board[0].length
let visited = new Array(row).fill(false).map(() => new Array(col).fill(false))
// 把边缘的都从O转化为了A
for (let i = 0; i < row; i++) 
    if (board[i][0] === "O") dfs(board, i, 0)
    if (board[i][col - 1] === "O") dfs(board, i, col - 1)

console.log(board)
for (let i = 0; i < col; i++) 
    if (board[0][i] === "O") 
        dfs(board, 0, i)
    
    if (board[row - 1][i] === "O") 
        dfs(board, row - 1, i)
    


console.log(board)
for (let i = 0; i < row; i++) 
    for (let j = 0; j < col; j++) 
        if (board[i][j] === "O") 
            board[i][j] = "X"
        
        if (board[i][j] === "A") 
            board[i][j] = "O"
        
    

return board
;


417. 太平洋大西洋水流问题(深搜、广搜)

var numIslands = function (grid) 
    // 使用dfs
    let dirx = [-1, 1, 0, 0]
    let diry = [0, 0, -1, 1]
    let row = grid.length
    let col = grid[0].length

    const dfs = function (grid, visited, i, j) 
        //终止条件
        //for循环
        for (let k = 0; k < 4; k++) 
            let x = i + dirx[k]
            let y = j + diry[k]
            if (x >= row || y >= col || x < 0 || y < 0) 
                continue
            
            if (visited[x][y] === false && grid[x][y] === '1') 
                visited[x][y] = true
                dfs(grid, visited, x, y)
            
        
    
    let visited = new Array(grid.length).fill(false).map(() => new Array(grid[0].length).fill(false))
    let count = 0
    for (let i = 0; i < row; i++) 
        for (let j = 0; j < col; j++) 
            if (visited[i][j] === false && grid[i][j] === '1') 
                visited[i][j] === true
                count++;
                dfs(grid, visited, i, j)
            

        
    

    return count
;


127. 单词接龙 (困难)
841. 钥匙和房间

bfs

var canVisitAllRooms = function(rooms) 
    // 使用dfs深度优先算法,使用visited记录访问过的屋子,使用key拿到钥匙
    const dfs = function(visited,room,key)
        // 终止条件
        if(visited[key])
            return
        
        // 单层递归逻辑
        visited[key] = true
        let keys = room[key]
        for(let i = 0;i<keys.length;i++)
            let newkey = keys[i]
            dfs(visited,room,newkey)
        
        // 返回值
    
    let visited = new Array(rooms.length).fill(false)
    dfs(visited,rooms,0)
    for(let visit of visited)
        console.log(visit)
        if(visit === false)
            return false
        
    
    return true
;

dfs 

var canVisitAllRooms = function(rooms) 
    // 使用dfs深度优先算法,使用visited记录访问过的屋子,使用key拿到钥匙
    const bfs = function(visited,room,key)
        // 终止条件
        let que = []
        que.push(room[key])
        // 单层递归逻辑
        visited[key] = true
        while(que.length>0)
            let keys = que.shift()
            for(let i = 0;i<keys.length;i++)
                let newkey = keys[i]
                if(visited[newkey] === true) continue
                visited[newkey] = true
                que.push(room[newkey])
            
        
    
    let visited = new Array(rooms.length).fill(false)
    bfs(visited,rooms,0)
    for(let visit of visited)
        if(visit === false)
            return false
        
    
    return true
;


每日精华:https://www.yuque.com/chengxuyuancarl/wnx1np/ktwax2,训练营群里讨论的问题,都会做总结,放在每日精华里,方便大家回顾。

https://excalidraw.com/
大家平时刷题可以用这个网站画草稿图帮助理解!
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
数据结构和算法可视化可以看这个网站!
 

图论算法小结

图论算法内容难度较大,且灵活多变,本篇是对前述内容的小结

1. 图论算法设计难点

(1)如何将一个实际问题转化成图上的搜索问题(建模难)

(2)如何选择最优的搜索方式,搜索代价的代价函数怎么设计(构造难)

2. 算法一览

(1)图论基本算法(DFS、BFS、最小生成树(prim(贪心)、kruskal(贪心))、最短路径(dijkstra(贪心)、floyd(动态规划)))

(2)网络流算法(FF算法):算法过程、算法证明(最大流和最小割的对偶性)

(3)最大二分匹配算法:FF算法(最大匹配和最小覆盖的对偶性)、匈牙利算法

(4)可行解的搜索算法:爬山法(局部贪心)、Best-first(全局贪心)

(5)最优解的搜索算法:分支界限(例:多阶段图最短路径问题、人员安排问题)、A*算法(例:最短路径问题)

以上是关于算法61天|图论的主要内容,如果未能解决你的问题,请参考以下文章

Matlab:数模05-图论模型(Floyd算法)

图论算法小结

图论最短路径问题(图的绘制以及Dijkstra算法和Bellman‐Ford算法)

图论最短路径问题(图的绘制以及Dijkstra算法和Bellman‐Ford算法)

从存图到最短路算法的图论总结

[算法模版]Tarjan爷爷的两种图论算法