图的遍历应用(C++)

题目1

在这里插入图片描述

收获

1:这道题重点地还是如何理解题目,知道要找是否存在唯一拓扑的话,解决起来就很容易了~
在这里插入图片描述

代码

#include <iostream>
#include <bits/stdc++.h>

using namespace std;
//有许多定义的方法,可以像我这样用参数的方法,同时如果不是递归的话,很多都可以使用全局变量解决~
//如果使用vector<int >g[n+1];这种定义方法的话,需要vector<int > g[]这种方法作为参数引用~
int islegel(vector<vector<int >>&g,vector<int >&input){
    int count=0;
    queue<int >q;
    for(int i=1;i<=input.size();i++){
        if(input[i]==0){
            count++;
            q.push(i);
            }
        if(count==2)
            return 0;
    }
    while(!q.empty()){
        if(q.size()>1)
            return 0;
        int u=q.front();
        q.pop();
        for(auto it:g[u]){
            input[it]--;
            if(input[it]==0)
                q.push(it);
        }
    }
    return 1;
}

int main()
{
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        vector<vector<int >>g(n+1);
        vector<int >input(n+1,0);
        while(m--){
            int x,y;
            cin>>x>>y;
            g[x].push_back(y);
            input[y]++;
        }
        cout<<islegel(g,input)<<endl;
    }
    return 0;
}

题目2(求两个顶点之间的一条路径长度最短的路径)

收获

1:这道题的收获是,学会了用自己定义的数据结构,结合图进行遍历寻找到一条路径,最后进行逆序输出,这道题是一种广度优先搜索的方法,每次都统计当前层和前一层之间的节点关系,然后front节点从投开始依次遍历~

代码

在这里插入图片描述

在这里插入图片描述

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

typedef struct{
    int data;//顶点编号
    int pre;
}Qu;
//非环形队列类型

void shortPath(vector<vector<int >>graph,int u,int v){
    Qu q[100];
    vector<bool>visited(graph.size(),false);
    int front1=-1, rear=0;
    q[rear].data=u;
    q[rear].pre=-1;
    visited[u]=true;
    while(front1!=rear){
        front1++;
        int w=q[front1].data;
        if(w==v){
            int i=front1;
            while(q[i].pre!=-1){
                cout<<q[i].data<<' ';
                i=q[i].pre;
            }
            cout<<q[i].data<<endl;
            break;
        }
        for(auto it:graph[w]){
            if(visited[it]==false){
                visited[it]=true;
                rear++;
                q[rear].data=it;
                q[rear].pre=front1;
            }
        }
    }
}

int main()
{
    int n,m;
    cin>>n>>m;
    vector<vector<int >>graph(n+1);
    for(int i=0;i<m;i++){
        int x,y;
        cin>>x>>y;
        graph[x].push_back(y);
        graph[y].push_back(x);
    }
    int u,v;
    cin>>u>>v;
    shortPath(graph,u,v);
    return 0;
}

题目3(所有可能的路径)

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

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

示例 1:
在这里插入图片描述

输入:graph = [[1,2],[3],[3],[]]
输出:[[0,1,3],[0,2,3]]
解释:有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3
示例 2:
在这里插入图片描述

输入:graph = [[4,3,1],[3,2,4],[3],[4],[]]
输出:[[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]]

提示:

n == graph.length
2 <= n <= 15
0 <= graph[i][j] < n
graph[i][j] != i(即不存在自环)
graph[i] 中的所有元素 互不相同
保证输入为 有向无环图(DAG)

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/all-paths-from-source-to-target
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

收获

1:这是自己做的第一道图的题,感觉好像和自己学习中学到的C语言写的图有丢丢区别,原来可以使用位置i表示一个节点,然后vector数组中的元素值表示节点连接的位置,这样也表示出来了一个图的样子,然后使用深度优先搜索添加路径,因为最开始已经有一个固定的值0,所以在最开始提前添加,然后仍然通过,循环和递归的方法实现回溯添加路径(这里自己好像感觉,如果想要获得路径的话,就要使用循环和递归的方法,单纯的递归有时好像会出现数组空等的问题)
2:感觉这里大概用了某种思想,深度递归一定会找到任何一点自己想要找的值,如果当前路径没有找到的话,就会选择回溯,结束当次循环~

代码

class Solution {
public:
    vector<vector<int >> result;
    vector<int >path;
    void dfs(vector<vector<int >>&graph,int x){
        //找到符合条件的一条路径
        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();
        }
    }
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
       path.push_back(0);
       dfs(graph,0);
       return result;
    }
};

题目4(克隆图)

给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。

图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。

class Node {
public int val;
public List neighbors;
}

测试用例格式:

简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1(val = 1),第二个节点值为 2(val = 2),以此类推。该图在测试用例中使用邻接列表表示。

邻接列表 是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。

给定节点将始终是图中的第一个节点(值为 1)。你必须将 给定节点的拷贝 作为对克隆图的引用返回。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/clone-graph
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

收获

1:学会了图的深度优先搜索克隆!结合map和深度优先~

代码

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> neighbors;
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};
*/

class Solution {
public:
    unordered_map<Node*,Node*>visited;
    Node* cloneGraph(Node* node) {
        if(node==nullptr){
            return node;
        }
        if(visited.find(node)!=visited.end()){
            return visited[node];
        }
        Node *cloneNode=new Node(node->val);
        visited[node]=cloneNode;
        /*for(auto&neighbor:node->neighbors){
            cloneNode->neighbors.emplace_back(cloneGraph(neighbor));
        }*/
        for(int i=0;i<node->neighbors.size();i++){
            cloneNode->neighbors.push_back(cloneGraph(node->neighbors[i]));
        }
        return cloneNode;
    }
};

题目5(课程表)

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。

例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:

输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

提示:

1 <= numCourses <= 105
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/course-schedule
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

收获

1:学会了一些关于图的出度入度的应用,课程表这道题是典型的应用,自己 在上课的时候也学过相关的知识(1)统计所有入度为0的节点入队列(2)遍历每一个队列的节点,将所有该点相关的映射的入度-1,如果减去1之后对应的入度变为0,那么就添加近队列,继续遍历队列~(3)最后统计最终结果的总数
2:最开始全部采用遍历的方法,没有巧妙的使用map这一方法,在最开始第一次遍历创建input时,同时创建每一个节点的出度映射,这样在后期对每一个节点相应的临界点入度-1时会比较方便,不会超时~

代码

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        vector<int >input(numCourses,0);
        //统计所有入度为0的节点
        unordered_map<int,vector<int >>mp;
        for(auto&pre:prerequisites){
            input[pre[0]]++;
            mp[pre[1]].push_back(pre[0]);
        }
        queue<int >q;
        for(int i=0;i<numCourses;i++){
            if(input[i]==0)
               q.push(i);
        }
        //出队列的时候将这个顶点所有的临界点的入度减1,并将队列的结果元素加入结合,如果入度为0
        //则继续入队列
        //最后检查结果集合中的元素是否和课程数相同
        int count=0;
        while(!q.empty()){
           int node=q.front();
           q.pop();
           count++;
           for(auto&num:mp[node]){
               input[num]--;
               if(input[num]==0)
                  q.push(num);
           }
        }
        return count==numCourses;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值