代码随想录刷题攻略---图论1-深搜1

例题1

所有可能的路径:给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序

 graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。

深搜三部曲

其实dfs的过程就是回溯算法的过程,框架是相通的

void dfs(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本节点所连接的其他节点) {
        处理节点;
        dfs(图,选择的节点); // 递归
        回溯,撤销处理结果
    }
}

1.确定递归函数及参数

在该题中,递归函数的参数是graph二维数组当前结点x

2. 确定终止条件

终止条件是当目前搜索到的路径没有下一个能访问的结点时,将该路径结果存储。所以终止条件是该结点为graph数组的最后一个元素

3.处理目前搜索节点出发的路径

每一次搜索中,先找当前节点x的邻接点有哪些,故遍历该结点的邻接结点graph[x][i],在每一轮遍历中,将一个邻接点加入当前路径再以邻接点为当前结点x,继续深搜,进入下一层递归,当递归结束并保存了遍历路径时,再进行回溯,撤销本节点

code

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
        path.push_back(0);
        dfs(graph,0);//当前结点是0
        return result;
    }

    void dfs(vector<vector<int>>& graph,int x)
    {
        //找出所有从节点 0 到节点 n-1 的路径,故graph.size()-1为结点个数
        if(x == graph.size()-1)
        {
            result.push_back(path);
            return ;
        }

        for(int i=0 ;i < graph[x].size() ; i++)
        {
            path.push_back(graph[x][i]);
            dfs(graph,graph[x][i]);
            path.pop_back();
        }
    }
};

例题2

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

深搜三部曲

1.确定递归函数及参数

在该题中,递归函数的参数是graph二维数组/当前结点x,y/是否访问过数组visted

2. 确定终止条件

处理函数numIslands中,我们对没有访问过的陆地结点先进行计数,每计数一次,则把该结点的连通节点全部标为ture,即已访问过。在后续的计数过程中不计入这些连通结点。终止条件是当目前搜索到的路径没有下一个能访问的结点时(即当前节点已经访问过或者当前节点是海洋而不是陆地)

3.处理目前搜索节点出发的路径

每一次搜索中,先访问结点(x,y)并将对应的visited数据元素置为true,然后深度搜索该结点的的正下方结点,再将该结点变为当前结点x,置为true后继续深搜,进入下一层递归,当递归结束后,再搜索当前结点的右/上/左边的结点并分别深搜。

code

class Solution {
public:
    int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
    int numIslands(vector<vector<char>>& grid) {
        int n = grid.size(), m = grid[0].size();
        vector<vector<char>> visited(n,vector<char>(m,false));//是否已访问过

        int res = 0;//岛屿数量
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
                {
                    if(!visited[i][j] && grid[i][j] == '1')//未访问过而且是陆地不是海
                        {
                            res++;//岛屿数量加一
                            dfs(grid,visited,i,j);//将这块陆地的邻接陆地全标为true,不参与下次的遍历
                        }
                }
        return res;
    }

    void dfs(vector<vector<char>>& grid,vector<vector<char>>& visited,int x,int y)
    {
        //深度遍历 x,y 结点的邻接点,将这些节点设为 访问过
        if(grid[x][y] == '0' || visited[x][y])//访问过此节点或碰到海水
            return;
        visited[x][y] = true;
        for(int i = 0; i < 4; i++)
        {
            int nextx = x + dir[i][0];
            int nexty = y + dir[i][1];
            if(nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size())
            continue;//越界,查看往其他地方走能不能行
            dfs(grid,visited,nextx,nexty);

        }
    }
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值